以前、JavaScript エンジンの解析メカニズムから JavaScript の動作原理を調べました。以下では、ページ内の JavaScript コードの実行順序を説明するために、より鮮明な例を使用します。 JavaScript エンジンの動作メカニズムが基礎的な動作に属しているため、比較的奥深い場合、JavaScript コードの実行順序はより鮮明になります。これは、JavaScript コードの実行順序を直感的に感じることができるためです。は比較的複雑であるため、JavaScript 言語について詳しく説明する前に、JavaScript 言語のプロファイルを作成することも必要です。
1.1 HTML ドキュメント フローの順序で JavaScript コードを実行する
まず、読者はブラウザでの HTML ドキュメントの解析プロセスが次のようなものであることを知っておく必要があります。ブラウザはドキュメント フローに従います。上から下へ 以下は、ページの構造と情報を段階的に分析したものです。埋め込みスクリプトとしての JavaScript コードも HTML ドキュメントのコンポーネントとしてカウントされる必要があるため、読み込み中の JavaScript コードの実行順序もスクリプト タグ <script> の出現順序に基づいて決定されます。たとえば、以下のドキュメント ページを参照すると、コードが上から下まで段階的に解析されていることがわかります。 </script>
外部 JavaScript ファイルのスクリプトがスクリプト タグ <script> の src 属性を通じてインポートされる場合、そのスクリプトもそのステートメントが出現する順序で実行され、実行プロセスはドキュメントの読み込みの一部となります。外部JavaScriptファイルなので実行が遅れることはありません。たとえば、上記のドキュメントのヘッド領域とボディ領域にあるスクリプトを外部 JavaScript ファイルに移動し、src 属性を通じてインポートします。ページドキュメントのプレビューを続けると、同じ実行順序が表示されます。 <br></p> <div class="codetitle"> <span><a style="CURSOR: pointer" data="39983" class="copybut" id="copybut39983" onclick="doCopy('code39983')"><u>コードをコピー</u></a></span> コードは次のとおりです:</div> <div class="codebody" id="code39983"> <br><script> <p>alert("トップスクリプト");</p> <p></script>
<スクリプト src="http://www.jb51.net/head.js">
<本体>
<スクリプト src="http://www.jb51.net/body.js">
alert("ボトムスクリプト");
1.2 プリコンパイルと実行順序の関係
JavaScript では、関数は Javascript の最初のタイプです。関数を記述するとき、実際には関数型のエンティティを作成しているだけです。
フォームで書くのと同じように:
alert(a);
var a =1;alert(a); // 戻り値 1
同様に、次の例では、関数が宣言される前に関数を呼び出すことは正当であり、正しく解析できるため、戻り値は 1 になります。
アラート(1);
}
アラート(1);
}
いくつかの例を見てみましょう:
変数と関数の宣言はドキュメント内のどこにでも置くことができますが、すべての JavaScript コードの前にグローバル変数と関数を宣言し、変数を初期化して代入することをお勧めします。関数内では、変数は最初に宣言されてから参照されます。
1.3 JavaScript コードをブロックで実行する
いわゆるコード ブロックは、<script> タグで区切られたコード セグメントです。たとえば、以下の 2 つの <script> タグは JavaScript コードの 2 つのブロックを表します。 </script>
// JavaScript コード ブロック 2
関数 f(){
アラート(1);
}
JavaScript インタープリターはスクリプトを実行する際、ブロック単位で実行します。平たく言えば、ブラウザが HTML ドキュメント ストリームを解析するときに <script> タグを検出すると、JavaScript インタプリタはコード ブロックがロードされるまで待機し、コード ブロックをプリコンパイルしてから実行します。実行後、ブラウザーは以下の HTML ドキュメント ストリームの解析を続け、JavaScript インタープリターはコードの次のブロックを処理する準備が整います。 </p> <p>JavaScript はブロック単位で実行されるため、後続のブロックで宣言された変数や関数を JavaScript ブロック内で呼び出すと、構文エラーが表示されます。たとえば、JavaScript インタプリタが次のコードを実行すると、変数 a が未定義でオブジェクト f が見つからないことを示す構文エラーが表示されます。 </p> <p></p> <div class="codetitle"> <span><a style="CURSOR: pointer" data="35451" class="copybut" id="copybut35451" onclick="doCopy('code35451')"><u>コードをコピー</u></a></span> コードは次のとおりです:</div> <div class="codebody" id="code35451"> <br><script> <p>// JavaScript コードブロック 1</p> <p>アラート(a);</p> <p>f();</p> <p></script>
// JavaScript コード ブロック 2
var a =1;
関数 f(){
アラート(1);
}
JavaScript はブロック内で実行されますが、異なるブロックは同じグローバル スコープに属します。これは、ブロック間の変数や関数を共有できることを意味します。
1.4 イベントメカニズムを使用して JavaScript の実行順序を変更する
JavaScript はコードをブロック単位で処理し、HTML ドキュメント フローの解析順序に従うため、上記の例ではこのような構文エラーが発生します。ただし、ドキュメント ストリームがロードされると、再度アクセスしてもこのようなエラーは発生しません。たとえば、コードの 2 番目のブロックの変数と関数にアクセスするコードがページ初期化イベント関数に配置されている場合、構文エラーは発生しません。
// JavaScript コード ブロック 2
var a =1;
関数 f(){
アラート(1);
}
セキュリティ上の理由から、通常、JavaScript コードの実行はページの初期化後にのみ許可されます。これにより、JavaScript の実行に対するネットワーク速度の影響が回避され、HTML ドキュメント フローによって引き起こされる JavaScript の実行の制限も回避されます。
注意
ページ内に複数の windows.onload イベント ハンドラーがある場合、最後のものだけが有効です。この問題を解決するには、すべてのスクリプトまたは呼び出し関数を同じ onload イベント ハンドラーに含めることができます。次に例を示します。 >
f2();
f3();
}
ページ初期化イベントに加えて、マウス イベント、キーボード イベント、クロック トリガーなどのさまざまなインタラクティブ イベントを通じて JavaScript コードの実行順序を変更することもできます。詳細な説明については、第 14 章を参照してください。
1.5 JavaScript 出力スクリプトの実行順序
JavaScript 開発では、JavaScript スクリプトを出力するためにドキュメント オブジェクトの write() メソッドがよく使用されます。では、これらの動的出力スクリプトはどのように実行されるのでしょうか?例:
上記のコードを実行すると、次のことがわかります。 document.write() メソッドは、まずスクリプトが配置されているドキュメントの場所に出力スクリプト文字列を書き込み、ブラウザはドキュメントのコンテンツを解析した後も解析を続けます。 document.write() が見つかりました。 document.write() によって出力されたコンテンツは、次の HTML ドキュメントを解析するために解析されます。つまり、JavaScript スクリプトが出力したコード列は、出力直後に実行されます。
document.write() メソッドを使用して出力される JavaScript スクリプト文字列は、同じく出力される <script> タグ内に配置する必要があることに注意してください。そうしないと、JavaScript インタプリタはこれらの正当な JavaScript コードを認識せず、通常のコードとして扱います。文字列はページドキュメントに表示されます。たとえば、次のコードは JavaScript コードを実行する代わりに表示します。 </p> <p></p> <div class="codetitle"> <span><a style="CURSOR: pointer" data="94458" class="copybut" id="copybut94458" onclick="doCopy('code94458')"><u>コードをコピー</u></a></span> コードは次のとおりです。</div> <div class="codebody" id="code94458"> <br>document.write('f(); '); <p>document.write('function f(){');</p> <p>document.write('alert(1);');</p> <p>document.write(');');<br></p> </div> <p>ただし、document.write() メソッドを介してスクリプトを出力および実行する場合には、一定のリスクが伴います。これは、JavaScript エンジンによってスクリプトが異なる順序で実行され、ブラウザによって解析にバグが発生する可能性があるためです。 </p> <p>Ø 問題 1: document.write() メソッドを通じてインポートされた外部 JavaScript ファイルで宣言された変数または関数が見つかりません。たとえば、以下のサンプルコードを見てください。 </p> <p></p> <div class="codetitle"> <span><a style="CURSOR: pointer" data="27974" class="copybut" id="copybut27974" onclick="doCopy('code27974')"><u>コードをコピー</u></a></span> コードは次のとおりです。</div> <div class="codebody" id="code27974"> <br>document.write('<script type ="text /javascript" src="http://www.jb51.net/test.js"> <p></script>');
document.write('');
Alert (n 1); // すべてのブラウザは変数 n が見つからないことを通知します
外部 JavaScript ファイル (test.js) のコードは次のとおりです。
Ø 質問 2: JavaScript エンジンが異なると、出力外部インポート スクリプトの実行順序が若干異なります。たとえば、以下のサンプルコードを見てください。
document.write('');
アラート(n 3);
アラート(n);
IE ブラウザでの実行シーケンスを図 1-6 に示します。
図 1-6 IE 7 ブラウザの実行シーケンスと表示される構文エラー
DOM 標準に準拠したブラウザでの実行順序は、IE ブラウザでの実行順序とは異なり、構文エラーはありません。図 1-7 は、Firefox 3.0 ブラウザでの実行順序を示しています。
図 1-7 Firefox 3 ブラウザの実行シーケンスと表示される構文エラー
さまざまなブラウザでのさまざまな実行順序と考えられるバグを解決します。出力スクリプトを使用してインポートされたすべての外部ファイルを独立したコード ブロックに配置できるため、上で紹介した JavaScript コード ブロックの実行順序に従ってこの問題を回避できます。たとえば、上記の例の場合、次のように設計できます:
document.write('');
alert(n 3) // ヒント 4
alert(n 4) // ヒント 5
このように、上記のコードは異なるブラウザで順番に実行でき、出力順序は 1、2、3、4、5 になります。問題の理由は、インポートされた出力スクリプトと現在の JavaScript コード ブロック間の矛盾です。別々に出力した場合は競合しません。