web-dev-qa-db-ja.com

変数が関数と等しいとはどういう意味ですか?

可能性のある複製:
JavaScript:var functionName = function(){} vs function functionName(){}

JavaScriptで、変数を関数として定義する目的は何ですか?私はこの慣習を以前に見たことがあり、完全に理解していません。

たとえば、スクリプトのある時点で、関数は次のように呼び出されます。

whatever();

しかし、次のようにwhateverという名前の関数が表示されることを期待します。

function whatever(){

}

代わりに、次のように、関数として定義されているwhateverという変数が表示されます。

var whatever = function(){

}

これの目的は何ですか?関数に名前を付けるだけでなく、なぜこれを行うのですか?

39
daGUY

:回答の最後の更新を参照してください。ブロック内の宣言が有効になりました(ただし、strictモードを使用していない場合はかなり複雑になります)。


これには1つの理由があります。

var whatever;

if (some_condition) {
    whatever = function() {
        // Do something
    };
}
else {
    whatever = function() {
        // Do something else
    };
}
whatever();

実装の違い(Webブラウザー間の違い、IEのattachEventと標準のaddEventListenerの違いなど)を処理する必要のあるライブラリーの初期化で、このようなコードが表示される場合があります。関数宣言では同等のことはできません。

if (some_condition) {
    function whatever() {    // <=== DON'T DO THIS
        // Do something
    }
}
else {
    function whatever() {    // <=== IT'S INVALID
        // Do something else
    }
}
whatever();

...それらは制御構造内で指定されていないため、JavaScriptエンジンは必要なことを実行でき、エンジンが異なれば実行も異なります。 (編集:繰り返しになりますが、以下の注を参照してください。これらは現在指定されています。)

別に、間に大きな違いがあります

var whatever = function() {
    // ...
};

そして

function whatever() {
    // ...
}

1つ目は関数式であり、コードがコンテキストの段階的な実行(たとえば、それが含まれている関数、またはステップ)のそのポイントに到達すると評価されます。グローバルコードの段階的実行)。また、anonymous関数になります(それを参照する変数には名前がありますが、関数にはありません。これは ツールを支援するのに役立ちます )。

2番目は関数宣言であり、コンテキストに入るときに評価されますbefore任意のステップ-ステップバイコードが実行されます。 (ソースでさらに下にある何かがソースで上のよりも前に発生するため、これを「巻き上げ」と呼ぶ人もいます。)関数には適切な名前も付けられます。

だから考慮してください:

function foo() {
    doSomething();
    doSomethingElse();
    console.log("typeof bar = " + typeof bar); // Logs "function"

    function bar() {
    }
}

一方

function foo() {
    doSomething();
    doSomethingElse();
    console.log("typeof bar = " + typeof bar); // Logs "undefined"

    var bar = function() {
    };
}

最初の例では、宣言を使用して、宣言がdoSomethingの前に処理され、他の段階的なコードが実行されます。 2番目の例では、であるため、ステップワイズコードの一部として実行され、関数は上で定義されていません(変数は上で定義されているため、 varも「巻き上げられます」 )。

そして最後に:今のところ、一般的なクライアント側のウェブではこれを行うことはできません。

var bar = function foo() { // <=== Don't do this in client-side code for now
    // ...
};

あなたはそれを行うことができるはずです、それは名前付き関数式と呼ばれ、関数に適切な名前を与える関数式です。しかし、さまざまなJavaScriptエンジンがさまざまなタイミングで誤解してきました IEはごく最近まで非常に誤解し続けていました


ES2015 +のアップデート

ES2015(別名 "ES6")以降、ブロック内の関数宣言が仕様に追加されました。

厳格モード

ストリクトモードでは、新しく指定された動作はシンプルで理解しやすくなっています。これらの動作は、発生したブロックにスコープが設定され、その最上部に引き上げられます。

したがって、この:

"use strict";
if (Math.random() < 0.5) {
  foo();
  function foo() {
    console.log("low");
  }
} else {
  foo();
  function foo() {
    console.log("high");
  }
}
console.log(typeof foo); // undefined

(関数への呼び出しがブロック内の関数のaboveであることに注意してください。)

...基本的にこれと同等です:

"use strict";
if (Math.random() < 0.5) {
  let foo = function() {
    console.log("low");
  };
  foo();
} else {
  let foo = function() {
    console.log("high");
  };
  foo();
}
console.log(typeof foo); // undefined

ルーズモード

ルーズモードの動作ははるかに複雑であり、さらに理論的には、WebブラウザーのJavaScriptエンジンとWebブラウザーのJavaScriptエンジンでは異なります。ここでは入りません。しないでください。ブロック内の関数宣言を主張する場合は、厳密モードを使用します。厳密モードは、意味があり、環境全体で一貫しています。

35
T.J. Crowder

これは、関数を変数に格納できるようにするためです。それらをパラメーターとして他の関数に渡します。これが有用な1つの例は、引数としてコールバックが渡される非同期関数の記述です。

var callback = function() { console.log('done', result)}

var dosomething = function(callback) {
    //do some stuff here
    ...
    result = 1;
    callback(result);
}

関数はJavaScriptのオブジェクトであるため、プロパティとメソッドを使用して拡張することもできます。

2
joidegn

JavaScriptの関数はオブジェクトです。つまり、それらはvaluesです。したがって、常に関数の定義方法に関係なく、変数を設定して関数を参照できます。

function foo() { ... }

var anotherFoo = foo;
anotherFoo(); // calls foo

関数は、オブジェクトのプロパティ、関数のパラメーター、配列要素など、JavaScriptで一般的な値として使用できるすべての値です。それらはオブジェクトであり、独自のプロパティを持つこともできます。

1
Pointy

関数を変数に割り当てると、その関数を引数として他の関数に渡し、JavaScriptのオブジェクトモデルを利用するように拡張することもできます。

1
lamplightdev

関数内で「var」を使用して関数変数を宣言すると、変数のみがその関数内でアクセスされます。関数を終了すると、変数は破棄されます。これらの変数はローカル変数と呼ばれます。それぞれが宣言されている関数によってのみ認識されるため、異なる関数で同じ名前のローカル変数を持つことができます。

0
Downpour046