関数実行環境
簡単なコード:
function Say(msg,other){
var str = "誰も言いません:";
this.name = '馬鹿の座右の銘'
function method(){};// var method = function(){};
alert(str msg);
say('hello world')
alert(name); // バカのモットー
say メソッドを呼び出すとき、最初のステップはその実行環境を作成することです。実行環境の作成プロセスでは、一連の操作が定義された順序で完了します。
1.アクティブ オブジェクト」が作成されます (アクティブ化オブジェクト)。アクティブ オブジェクトは、仕様で指定されているもう 1 つのメカニズムです。アクセス可能な名前付きプロパティがあるため、オブジェクトと呼ばれますが、通常のオブジェクトのようなプロトタイプ (少なくとも事前定義されたプロトタイプ) はなく、アクティブなオブジェクトは JavaScript コードを通じて直接参照できません。
2. 関数呼び出しの実行環境を作成する次のステップは、引数オブジェクトを作成することです。これは、関数を呼び出すときに渡されるパラメーターを整数インデックスと 1 対 1 対応で格納する配列のようなオブジェクトです。配列のメンバー。このオブジェクトには長さと呼び出し先のプロパティもあります (詳細については、「Javascript_14_Function のパラメータと引数について」を参照してください)。次に、アクティブ オブジェクトに対して「arguments」と呼ばれるプロパティが作成され、前に作成したarguments オブジェクトを参照します。
3. 次に、実行環境にスコープを割り当てます。スコープはオブジェクトのリスト (チェーン) で構成されます。 (さらに複雑です。「JavaScript_15_Scope の割り当てと変数アクセス ルールを理解してクロージャを送信する」を参照してください)
4. その後、ECMA 262 のいわゆる「アクティブ オブジェクト」によって完了した「変数のインスタンス化」が発生します (変数のインストール) プロセス。このとき、関数の仮引数は変数オブジェクトの名前付きプロパティとして作成され、関数呼び出し時に渡される引数が仮引数と一致する場合には、対応する引数の値がこれらの名前付きプロパティに代入されます。プロパティ (そうしないと、名前付きプロパティに未定義の値が割り当てられます)。定義された内部関数の場合、宣言された名前を持つ可変オブジェクト上に同じ名前のプロパティが作成され、対応する内部関数が関数オブジェクトとして作成され、そのプロパティに割り当てられます。変数のインスタンス化の最後のステップは、関数内で宣言されたすべてのローカル変数を可変オブジェクトの名前付きプロパティとして作成することです。注: このプロセスでは、値を持つ実際のパラメーターと関数定義を除き、その他すべては未定義の値として「事前解析」されます。
5 最後に、this キーワードを使用するために値を割り当てる必要があります。 。 (この時点では、グローバル オブジェクト、つまりウィンドウを指します)
実行環境が正常に作成されたら、2 番目のステップに入ります。関数本体の上から下にコードを実行します。
1. var str='nobodysay' が実行されると、「計算代入式」と呼ばれる処理が発生し、アクティブなオブジェクトのキー str の値が unknown から 'nobodysay: に設定されます。 '。
2. this.name='バカの座右の銘' を実行すると、属性名が this としてオブジェクトに追加され、値が 'バカの座右の銘' として割り当てられます。
3. 次に function innerMethod(){ };最後に 'alert(str msg) を実行し、'nobodysay:hello world' を出力します。
function method(){} と var method(){}
簡単なコード: function Say(){
method01();//method01
method02();//エラー
function method01(){
alert('method01')
}
var method02 = function( ) {
alert('method02')
}
}
say();
メソッドmethod01の呼び出しは正常に実行されるのに、メソッドmethod02の呼び出しではエラーが報告されるのはなぜですか? まず、method01 は関数オブジェクトであり、method02 は別の関数オブジェクトを指す変数であることを明確に理解しておく必要があります。前のセクションの内容によると、「アクティブ オブジェクト」によって完了する「変数の初期化」のプロセスでは、関数メソッド 01 は通常「事前解析」され、変数メソッド 02 は When に入るときに未定義の値に解析されます。コードを実行することになりますが、関数式を計算する前にmethod02が呼び出されるため、メソッド呼び出しとしてunknownが使用されている場合、必然的にエラーが報告されます。解決策は比較的簡単で、method02() の呼び出しの前に var method02=function(){...} を置くか、関数宣言 (function method(){...}) の形式で関数を定義するだけです。
注: 関数式の計算とは、var method02 = function(){...} までプログラムが実行されることを意味します。この時点では実際には、method02 は関数オブジェクトを指しています。 「事前解析」中に、method02 は未定義の
グローバル実行環境 (「実行モデル分析」で既に説明されているため、詳細は説明しません)
にのみ割り当てられたためです。グローバル実行環境は、JS コードが初めてロードされるときに作成されます。グローバル実行環境のスコープ チェーンは、実際には、JavaScript コードの実行を開始する前に、グローバル オブジェクト (ウィンドウ) という 1 つのオブジェクトのみで構成されます。エンジンはこのスコープ チェーン構造を作成します。グローバル実行環境には変数のインスタンス化プロセスもあり、その内部関数は、ほとんどの JavaScript コードを含む通常のトップレベル関数宣言です。さらに、グローバル オブジェクトは変数のインスタンス化中に可変オブジェクトであるため、グローバルに宣言された関数はグローバル オブジェクト プロパティになります。グローバルに宣言された変数にも同じことが当てはまります。グローバル実行環境は、このオブジェクトを使用してグローバル オブジェクトを参照します。
注: 「関数実行環境」のアクティベーション オブジェクトとグローバル実行環境の変数オブジェクトを区別してください (いくつかの違いがあるため、新しい名前が付けられています)。違いを示すために仕様ではグローバル実行環境/Eval 実行環境では Variable オブジェクトと呼ばれ、関数実行環境では Activation オブジェクトと呼ばれます。
Eval 実行環境
Eval 実行環境構築時の変数オブジェクト (Variable Object) は、eval 呼び出し時の現在の実行コンテキストの変数オブジェクト (Variable Object) です。 eval 関数がグローバル実行環境で呼び出される場合、その変数オブジェクト (Variable Object) はグローバル オブジェクトであり、eval 関数が呼び出される場合、その変数オブジェクト (Variable Object) は関数のアクティベーション オブジェクト (Activation Object) になります。
//FF2.0、IE7 で渡されます。 、Opera9. 25、Safari3.0.4
function fn(arg){
var innerVar = "関数内の変数";
eval('
var evalVar = "eval 内の変数";
document.write (arg "
");
document.write(innerVar "
");
document.write(evalVar) ;
}
fn("arguments for function");
出力結果は次のようになります:
関数の変数 eval の変数
注: 関数 fn のパラメーターとローカル変数は、eval 呼び出しでアクセスできます。eval で定義されたローカル変数は、変数オブジェクトが同じオブジェクトであるため、関数 fn からもアクセスできます。 。
評価コードの実行に入ると、新しいスコープ チェーンが作成されます。その内容は、現在の実行コンテキストのスコープ チェーンとまったく同じです。
最後の例
コードは次のとおりです:
var innerVar1="グローバル コードの変数";
function fn1(arg1, arg2){
var innerVar1="関数コードの変数"; >関数 fn2() { return innerVar1 " - " innerVar1 " - " " - " (arg1 arg2) }
return fn2();
var innerVar2=fn1(10, 20); 🎜>
実行プロセスは大まかに次のとおりです。
1. ウィンドウ オブジェクトであるグローバル オブジェクトとウィンドウ オブジェクト自体である変数オブジェクトを初期化します。ウィンドウ オブジェクトのみを含むスコープ チェーン オブジェクトをscope_1 であると仮定して、スコープ チェーン オブジェクトを作成します。
2. JS ソース コードをスキャンします (ソース コードを読みます。字句解析および構文解析のプロセスがある場合があります)。その結果から、定義された変数名と関数オブジェクトを取得できます。スキャン順序に従って:
2.1 変数 externalVar1 を検出し、outerVar1 属性をウィンドウ オブジェクトに追加します。値は未定義です。
2.2 関数 fn1 の定義を検出し、この定義を使用して関数オブジェクトを作成します。作成プロセスに渡されるスコープ チェーンはscope_1です。結果を window プロパティに追加します。名前は fn1 で、値は返された関数オブジェクトです。 fn1 の内部 [[Scope]] はscope_1 であることに注意してください。なお、作成処理では関数本体内のJSコードに対して特別な処理は行わず、関数本体内のJSコードのスキャン結果を関数オブジェクトの内部プロパティに保存するだけであることが分かります。関数の実行時に処理されます。これは、関数コード、特に入れ子関数定義における変数のインスタンス化を理解するための鍵です。
2.3 変数 externalVar2 を検出し、outerVar2 属性をウィンドウ オブジェクトに追加します。値は未定義です。
3.そして値を「グローバルコード内の変数」に割り当てます。
4. 関数 fn1 を実行し、戻り値を取得します。
4.1 アクティベーション オブジェクトを作成します (有効化_1 であると仮定します)。新しいスコープ チェーンを作成します (有効範囲_2 の最初のオブジェクトが有効化_1 であると仮定します)。 object はウィンドウ オブジェクトです (fn1 の [[Scope]]、つまり、scope_1 の内容から取得されます)。
4.2 プロセス パラメーター リスト。 activity_1 の属性 arg1 と arg2 にそれぞれ値 10 と 20 を設定します。引数オブジェクトを作成して設定し、引数を activity_1 の属性として設定します。
4.3 fn1 の関数本体に対して手順 2 と同様のプロセスを実行します。
4.3.1 変数 innerVar1 を検出し、innerVar1 属性を追加します。 activity_1 オブジェクト、値は undefine;
4.3.2 関数 fn2 の定義を検出し、この定義を使用して関数オブジェクトを作成し、作成プロセスに渡されるスコープ チェーンはscope_2 です (関数 fn1 のスコープ チェーンは現在の実行コンテキストの内容)。結果を、fn2 という名前と返された関数オブジェクトの値を使用して、activation_1 の属性に追加します。 fn2 の内部 [[スコープ]] はscope_2 であることに注意してください。
4.4 innerVar1 代入ステートメントを実行し、値を「関数コード内の変数」に代入します。
4.5 fn2 を実行します。
4.5.1 アクティベーション オブジェクトを作成します (activation_2 であると仮定します); 新しいスコープ チェーンを作成します (scope_3 であると仮定します)。 . オブジェクト (fn2 の [[Scope]]、つまりscope_2 から取得);
4.5.2 プロセスパラメータリスト。 fn2 にはパラメーターがないため、引数オブジェクトを作成し、それを activity_2 の属性として設定するだけです。
4.5.3 fn2の関数本体に対して手順2と同様の処理を行うと、変数定義や関数宣言が見つかりません。
4.5.4 関数本体を実行します。変数参照の場合、scope_3 から検索します。この例では、outerVar1 は window で見つかり、innerVar1、arg1、および arg2 は activity_1 で見つかります。
4.5.5 スコープ_3 とアクティベーション_2 を破棄します (ガベージ コレクションできることを意味します)。
4.5.6 fn2の戻り値を返します。
4.6 activity_1 とscope_2 を破棄します。
4.7 結果を返します。
5. 結果をouterVar2に代入します。
参考:
http://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html
http://www .cn-cuckoo.com/2007/08/01/ Understand-javascript-closures-72.html