190

このコードは、異なるブラウザーでも常に機能します。

function fooCheck() {
  alert(internalFoo()); // We are using internalFoo() here...

  return internalFoo(); // And here, even though it has not been defined...

  function internalFoo() { return true; } //...until here!
}

fooCheck();

ただし、なぜそれが機能するのかについての単一の参照が見つかりませんでした。これは John Resig のプレゼンテーション ノートで初めて見ましたが、言及されただけでした。その点については、そこにもどこにも説明がありません。

誰かが私を啓発してもらえますか?

4

7 に答える 7

238

宣言は魔法であり、functionコードブロック* 内の何かが実行される前に、その識別子がバインドされます。

functionこれは、通常の上から下の順序で評価される式による代入とは異なります。

例を次のように変更した場合:

var internalFoo = function() { return true; };

それは機能しなくなります。

関数宣言は、ほとんど同じように見え、場合によってはあいまいになる可能性がありますが、構文的には関数式とはまったく別のものです。

これは、ECMAScript 標準のセクション10.1.3に記載されています。残念ながら、ECMA-262 は標準規格から見てもあまり読みやすいドキュメントではありません!

*: 含まれている関数、ブロック、モジュール、またはスクリプト。

于 2008-11-04T12:13:30.430 に答える
14

ブラウザーは HTML を最初から最後まで読み取り、読み取られて実行可能なチャンク (変数宣言、関数定義など) に解析されると、HTML を実行できます。

これは、すべてのソース コードを処理 (コンパイル) し、参照を解決するために必要なライブラリと一緒にリンクし、実行可能なモジュールを構築する他のプログラミング コンテキストとは異なります。この時点で実行が開始されます。

コードは、後で定義された名前付きオブジェクト (変数、その他の関数など) を参照できますが、すべての部分が利用可能になるまで参照コードを実行することはできません。

JavaScript に慣れてくると、適切な順序で記述する必要性を深く認識できるようになります。

リビジョン: 受け入れられた回答 (上記) を確認するには、Firebug を使用して Web ページのスクリプト セクションをステップスルーします。実際にコードを実行する前に、関数から関数へとスキップし、最初の行だけにアクセスすることがわかります。

于 2008-11-04T11:58:23.563 に答える
4

一部の言語では、使用前に識別子を定義する必要があります。これは、コンパイラがソースコードに対して単一のパスを使用するためです。

しかし、複数のパスがある場合 (またはいくつかのチェックが延期された場合) は、その要件なしで完全に生きることができます。この場合、おそらく最初にコードが読み取られ (そして解釈され)、次にリンクが設定されます。

于 2008-11-04T11:47:21.840 に答える
1

私は JavaScript を少ししか使用していません。これが役立つかどうかはわかりませんが、あなたが話していることと非常によく似ており、いくつかの洞察を与えるかもしれません:

http://www.dustindiaz.com/javascript-function-declaration-ambiguity/

于 2008-11-04T11:41:50.867 に答える
1

関数「internalFoo」の本体は、解析時にどこかに移動する必要があるため、コードが JS インタープリターによって読み取られる (別名解析) ときに、関数のデータ構造が作成され、名前が割り当てられます。

後でコードが実行され、JavaScript は実際に「internalFoo」が存在するかどうか、それが何であるか、呼び出すことができるかどうかなどを調べようとします。

于 2008-11-04T11:52:31.783 に答える
-4

同じ理由で、以下は常にfooグローバル名前空間に配置されます。

if (test condition) {
    var foo;
}
于 2008-11-04T17:38:23.690 に答える