67

JavaScriptプログラムは、ステートメントと関数宣言で構成されています。JavaScriptプログラムを実行すると、次の2つの手順が実行されます。

  1. コードは、関数宣言とすべての関数についてスキャンされます。宣言は(関数オブジェクトを作成することによって)「実行」され、その関数への名前付き参照が作成されます(この関数をステートメント内から呼び出すことができるように)

  2. ステートメントは順番に実行(評価)されます(コードに表示されるとおり)

そのため、これは問題なく機能します

<script>
    foo();
    function foo() {
        return;
    }
</script>

「foo」関数は宣言される前に呼び出されますが、関数宣言はステートメントの前に評価されるため、機能します。

ただし、これは機能しません

<script>
    foo();
</script>
<script>
    function foo() {
        return;
    }
</script>

ReferenceErrorがスローされます(「fooが定義されていません」)。これにより、WebページのHTMLコード内のすべてのSCRIPT要素が個別のJavaScriptプログラムを表し、HTMLパーサーがSCRIPT要素に遭遇するたびに、その要素内のプログラムを実行する(そして、プログラムが実行されると、パーサーは、SCRIPT要素に続くHTMLコードに移動します)。

次に、これは機能します:

<script>
    function foo() {
        return;
    }
</script>
<script>
    foo();
</script>

ここでの私の理解は、グローバルオブジェクト(グローバル実行コンテキストで変数オブジェクトとして機能する)は常に存在する(そして残る)ので、最初のJavaScriptプログラムが関数オブジェクトを作成し、それを参照し、次に2番目のJavaScriptプログラムは、その参照を使用して関数を呼び出します。したがって、すべてのJavaScriptプログラム(単一のWebページ内)は同じグローバルオブジェクトを「使用」し、1つのJavaScriptプログラムによってグローバルオブジェクトに加えられたすべての変更は、その後に実行されるすべてのJavaScriptプログラムで監視できます。

さて、これに注意してください...

<script>
    // assuming that foo is not defined
    foo();
    alert(1);
</script>

上記の場合、 「foo()」ステートメントがReferenceError(JavaScriptプログラム全体を破壊する)をスローするため、アラート呼び出しは実行されません。したがって、後続のすべてのステートメントは実行されません。

ただし、この場合は...

<script>
    // assuming that foo is not defined
    foo();
</script>
<script>
    alert(1);
</script>

これで、アラート呼び出しが実行されます。最初のJavaScriptプログラムはReferenceErrorをスローします(そして結果として壊れます)が、2番目のJavaScriptプログラムは正常に実行されます。もちろん、ブラウザはエラーを報告します(ただし、エラーが発生した後、後続のJavaScriptプログラムを実行しました)。

さて、私の結論は次のとおりです。

  • WebページのHTMLコード内のすべてのSCRIPT要素は、個別のJavaScriptプログラムを表します。これらのプログラムは、HTMLパーサーがそれらに遭遇するとすぐに実行されます。
  • 同じWebページ内のすべてのJavaScriptプログラムは、同じグローバルオブジェクトを「使用」します。そのグローバルオブジェクトは常に存在します(Webページがフェッチされた瞬間からWebページが破棄されるまで)。JavaScriptプログラムはGlobalオブジェクトを操作する場合があり、1つのJavaScriptプログラムによってGlobalオブジェクトに加えられたすべての変更は、後続のすべてのJavaScriptプログラムで監視できます。
  • 1つのJavaScriptプログラムが(エラーがスローされることによって)壊れた場合でも、後続のJavaScriptプログラムの実行が妨げられることはありません。

この投稿を事実確認して、何か問題があったかどうか教えてください。

また、この投稿で言及されている動作を説明するリソースは見つかりませんでした。ブラウザメーカーはそのようなリソースをどこかに公開しているはずなので、それらについて知っている場合は、それらへのリンクを提供してください。

4

4 に答える 4

19

関数ホイスト(関数functionの残りの部分の前にステートメントを評価するプロセス)は、ECMAScript標準IIRCの一部です(現在、参照を見つけることができませんが、それについて言及しているEMCAScriptの議論を見たことを思い出します)。タグの評価はscriptHTML標準の一部です。多くの言葉で「別個のプログラム」であるとは明記されていませんが、スクリプト要素はドキュメントに表示されている順序で評価されると言っています。これが、後のスクリプトタグの関数が引き上げられない理由です。スクリプトはまだ評価されていません。これは、1つのスクリプトの停止が後続のスクリプトを切断しない理由も説明しています。現在のスクリプトが評価を停止すると、次のスクリプトが開始されます。

于 2010-09-17T18:25:09.270 に答える
15

ドミトリー・ソシュニコフがあなたの質問に答えました。<script>ECMAScript仕様で定義されているように、すべての要素はプログラムとして実行されます。1ページ内の各プログラムが使用するグローバルオブジェクトが1つあります。そして、それは本当にそれです。

于 2010-10-19T11:18:39.283 に答える
7

これらは別個のプログラムですが、共有グローバルオブジェクトを変更します。

于 2010-09-17T17:05:28.537 に答える
4

これについて考える別の方法は、疑似ローカルスコープとグローバルスコープです。すべてのSCRIPT宣言には、現在のメソッド/関数へのローカルスコープと、現在の(以前に宣言された)グローバルスコープへのアクセスがあります。メソッド/関数がSCRIPTブロックで定義されると、それはグローバルスコープに追加され、その後SCRIPTブロックからアクセスできるようになります。

また、スクリプトの宣言/処理/変更に関するW3Cからのさらなるリファレンスは次のとおりです。

ドキュメントの動的な変更は、次のようにモデル化できます。

  1. すべてのSCRIPT要素は、ドキュメントがロードされるときに順番に評価されます。
  2. SGMLCDATAを生成する特定のSCRIPT要素内のすべてのスクリプト構成が評価されます。それらを組み合わせて生成されたテキストは、SCRIPT要素の代わりにドキュメントに挿入されます。
  3. 生成されたCDATAが再評価されます。

これは、スクリプト/関数の評価/宣言に関するもう1つの優れたリソースです。

于 2010-10-20T21:27:36.753 に答える