[JS前進の前奏]作用ドメインチェーン、クローズド、メモリ----Javascriptの実行過程詳細研究


1、html文書の流れ順にjavascriptコードを実行する
ブラウザは、文書の流れに従ってページ構造と情報を上から下へ徐々に解析していくもので、javascriptコードは埋め込まれたシナリオとしてhtmlドキュメントの構成部分を示しているので、javascriptコードのロード時の実行順序は、スクリプトラベル<script>の出現順序によって決定される.スクリプトラベル<script>のSrc属性によって外部.jsファイルが導入されると、そのステートメントの順序に従って実行され、実行プロセスはドキュメントローディングの一部である.外部のjsファイルだからといって、実行を延期することはありません.
2、プリコンパイルと実行順序の関係
1)情景の関数処理の原理は、まず次のコードを見ます.
<script type="text/javascript"> function hello() { alert("hello"); } hello(); function hello() { alert("hello world"); } hello(); </script>

//hello world 、hello world
出力結果はまずハローを出力してからハローワールドを出力するのではありません.これはjavascriptが完全に順を追って解釈して実行するのではなく、説明する前にjavascriptを一度プリコンパイルして、プリコンパイルする過程で、定義式の関数を優先的に実行し、すべてのvar変数を作成し、デフォルト値はundefinedとなり、プログラムの実行効率を高めるためです.つまり、上のコードはJSエンジンによってプリコンパイルされています.
<script type="text/javascript"> var hello = function() { alert("hello"); }; hello = function() { alert("hello world"); }; hello(); hello(); </script>
上のコードによって、関数も変数であり、関数に値を割り当てることができます.前のような状況を防ぐために、以下のように二つのjsファイルに定義されています.
<script type="text/javascript"> hello(); function hello() { alert("hello"); } </script>

<script type="text/javascript"> function hello() { alert("hello world"); } hello(); </script>
上の最初のファイルは私がfunctionの前にハローを置いても正しい結果が出力されます.2)情景二関数表現と関数宣言の違い
<script type="text/javascript"> hello(); var hello = function() { alert("hello"); }; </script>
上記のような方法でfunction関数を定義すると、hello is not a funtionと間違えます.これはプリコンパイルの際にvarで宣言した変数に対して、最初に処理しましたが、変数値はundefinedとなります.そしてハローを実行する時、前のハローはundefinedですので、タイプは決まっていません.だからここはハローis not a functionです.プログラムにはこの関数が定義されていますが、呼び出しの後に定義された位置が置かれていますので、呼び出し時にはプログラムはここに実行されていませんので、無駄です.
次のコードを見てください.
<script type="text/javascript"> hello(); function hello() { alert("hello"); } </script>
上記のコードはコールも関数定義の前にありますが、ここではfunctionキーワードで定義されています.functionで定義した場合は、varとは異なり、functionで定義したときに関数の値が割り当てられていますので、ここで実行できます.
3)まとめ
Javascriptエンジン解析スクリプトの場合は、事前翻訳期間中にすべての宣言の変数と関数を処理します.処理は以下の通りです
(1)実行前に「プリコンパイル」のような動作が行われます.まず現在実行されている環境での活動対象を作成し、varで宣言されている変数を活動対象の属性に設定します.ただし、これらの変数の割当値はundefinedです.また、functionで定義されている関数も活動対象の属性に追加されます.そして、それらの値は関数の定義です.
(2)実行段階を説明し、変数が解析される必要がある場合は、まず現在実行されている環境のアクティブオブジェクトから検索します.その実行環境の所有者がprototype属性を持っていない場合はprototypeチェーンから検索します.そうでない場合は、スコープで検索します.var a=...このようなステートメントに遭遇すると、対応する変数に値が割り当てられます.
(3)以上のように、一言でまとめると、変数の宣言はプリコーディング期間にあり、変数の初期化は稼働期間にあります.
ケース1:
<script type="text/javascript"> alert(a); //       a      ,   var  ,     undefined ,     undefined。 var a = 1; //            a     1 alert(a); //      a         ,    1。 </script>
上記のコードに対して、出力結果はundefinedを先に出力し、後に1を出力し、コードの備考を参照してください.実例二:(関数アップの概念は、見た:関数アップの例)
<script> var name = "feng"; function func(){ /*  , func     name   undefined,           func         name  ,           undefined,     undefined,   feng*/ alert(name); //undefined  var name = "JSF"; alert(name); //JSF  } func(); </script>
実例二:プリコンパイル段階でfunctionでvar name="JSF"–name=undefined;実行段階において、関数内で初めてalert(name)があるかどうかは、まずfunction内でその変数があるかどうかの声明を探します.コンパイル時にすでにローカル変数nameにundefinedを割り当てています.実行時は順次実行しますので、実行結果はfengでもJSFでもありません.変数と関数宣言はドキュメントの任意の位置にありますが、良い習慣はすべてのJavaScriptコードの前に大域変数と関数を宣言し、変数を初期化します.関数内でも先に変数を宣言してから参照します.
3、ブロック別にjavascriptコードを実行する
コードブロックとは、<script>タグで区切られたコードセグメントのことです.JavaScript解釈器はスクリプトを実行する時、ブロックで実行します.一般的には、ブラウザがHTMLファイルのストリームを解析する時に、もし一つの<script>タグがあったら、JavaScript解釈器はこのコードブロックが全部ロードされた後、先にコードブロックをプリコンパイルしてから実行します.実行が完了すると、ブラウザは次のHTMLファイルの流れを解析し続けます.また、JavaScriptのインタプリタも次のコードブロックを処理する準備ができています.JavaScriptはブロックごとに実行されますので、JavaScriptブロックの中で後ろのブロックに宣言されている変数または関数を呼び出したら文法エラーが発生します.
<script> alert(a); </script>

<script> var a = 1; </script>
上のコードは二つのコードブロックなので、最初のコードブロックを実行してから、二つ目のコードブロックを実行します.最初のコードブロックを実行する時、変数aは声明がないので、エラーメッセージは:a is not definedです.
<script> var a = 1; </script>

<script> alert(a); </script>
JavaScriptはブロックごとに実行されるが、異なるブロックは同じグローバルスコープ、すなわちブロック間の変数と関数を共有することができる.したがって、上の二つのコードブロックが動作しているときは、二つのコードブロックですが、第1のセグメントが実行されると、a変数は大域的な作用領域に存在します.このとき、第2のコードブロックに動作し、出力されたa変数は大域的な作用領域のaを呼び出すことができますので、問題はありません.
4、イベントのメカニズムによってjavascriptの実行順序を変更する
JavaScriptはブロックごとにコードを処理していますが、HTMLファイルストリームの解析順に従っていますので、上記の例ではこのような構文エラーが見られます.しかし、ドキュメントフローの読み込みが完了すると、再度アクセスするとこのようなエラーは発生しません.セキュリティのために、私たちは通常、ページ初期化が完了してからJavaScriptコードの実行を許可します.これにより、JavaScript実行に対するネットの速度の影響を避けることができます.また、HTMLドキュメントフローのJavaScript実行に対する制限も避けられます.
<script> window.onload = function() { alert(a); }; </script>

<script> var a = 1; alert("bb"); </script>
</head>
<body>

</body>
<script> alert("cc"); </script>
windows.onload=function()は、トリガイベントに関数を付けて、すぐに実行するのではなく、ページ全体にロードが完了したら、そのイベントの実行を開始します.ですから、Windows.onloadを実行する前に、一部の変数をグローバルエリアにロードしましたので、大丈夫です.上記の出力結果はbbを出力してccを出力し、最後にaの値を出力します.
<script> window.onload = function() { alert(a); }; //    onload    ,       onload window.onload = function() { alert("onload2"); }; </script>

<script> var a = 1; alert("bb"); </script>
</head>
<body>

</body>
<script> alert("cc"); </script>
一つのページに複数のwindows.onloadイベント処理関数が存在する場合、最後の一つだけ有効です.この問題を解決するために、すべてのスクリプトまたは呼び出し関数を同じonloadイベント処理関数に置くことができます.
5、javascript出力スクリプトの実行手順
JavaScriptの開発では、しばしばdocumentオブジェクトのwrite()を使ってJavaScriptスクリプトを出力します.Dcument.write()メソッドはまず出力されたスクリプト文字列をスクリプトがあるドキュメント位置に書き込み、ブラウザはdocument.write()がある文書の内容を解析した後、document.write()が出力した内容を解析し続けて、後のHTML文書を順次解析します.つまり、JavaScriptスクリプトから出力されたコード文字列は、出力後すぐに実行されます.Dcument.write()法を用いて出力されるJavaScriptスクリプト文字列は、同時に出力される<script>タグに置かなければならない.そうでなければ、JavaScript解釈器は、これらの適法なJavaScriptコードを識別することができないので、通常の文字列としてページファイルに表示される.しかし、Dcument.write()方法でスクリプトを出力して実行するには一定のリスクがあります.JavaScriptエンジンによって実行順序が異なり、ブラウザによっては解析時にBugが表示されます.
次のページ:[JSステップ0]作用ドメインチェーン、クローズド、メモリ-(匿名関数)は直ちに関数/オブジェクトの即時初期化を実行します.