Prototype の仕組みによれば、オブジェクト cf1、cf2 などはすべてオブジェクト Cfp のプロパティやメソッドを継承していると言え、それらの間には継承関係があると言えます。属性の継承/共有は暗黙のプロトタイプ チェーンに沿って機能するため、継承関係もこのチェーンに沿ったものとして理解される必要があります。
もう一度、instanceOf 操作を見てみましょう。cf1 のinstanceOf CF のみが true であり、cf1 が Cfp のインスタンス オブジェクトであると言うのではなく、CF がクラスの役割を果たします。 cf1 は CF から継承すると言うべきでしょうか? しかし、CF はサードパーティ ファクトリとして機能するだけであり、cf1 との間に属性の継承関係はありません。
プロトタイプはプロトタイプです。JavaScript とオブジェクト指向の概念を無理に組み合わせる必要はありません。別の観点から見ると、JavaScript は関数型言語または動的言語とみなすことができます。複数の言語機能を組み込んだ合理化されたバージョンです。
1. JavaScript のデータ型を理解し、Number のようなシステム組み込みオブジェクトには複数の ID があることを理解します。 a) それら自体は関数オブジェクトです。それらはエンジンによって内部的に実装されます。 b) それらはデータ型を表し、対応するデータ型を定義および操作するために使用できます。 c) それらの背後には、内部データ構造などのエンジンの内部実装メカニズムが隠されています。 JavaScript オブジェクトなどのコンストラクターになります。
2. プロトタイプのメカニズム、オブジェクトがそれらを介してプロパティとメソッドを継承する方法、およびオブジェクト作成プロセス中に JS エンジン内でプロトタイプ関係がどのように設定されるかを理解します。
JavaScript コードで関数を定義するとき、または Function を呼び出して関数を作成するとき、Function 関数は最終的に次のような形式で呼び出されます: var newFun=Function(funArgs,楽しいボディ);。関数オブジェクトを作成する主な手順は次のとおりです。
1. 組み込みオブジェクト fn を作成します
2. fn の内部 [[Prototype]] を Function.prototype に設定します
4. 内部 [[Construct]] 属性。論理参照を処理する内部実装メソッドです。オブジェクト作成プロセスのステップ 1、2、3、4
5. fn.length を funArgs.length に設定します。関数にパラメータがない場合は、fn.length を 0 に設定します。
6. new Object() Object オブジェクト fnProto
を作成します。 7. fnProto.constructor を fn
に返します。 ステップ 1 とステップ 6 の違いは次のとおりです。そのステップ 1 は、Object オブジェクトの実装に使用される内部データ構造 (組み込みオブジェクト構造) を作成し、必要な内部初期化作業を完了するだけですが、その [[Prototype]]、[[Call]]、[[Construct]]他の属性は null または内部初期化値である必要があります。つまり、オブジェクトを指していない ([[Prototype]] などのプロパティの場合)、または処理が含まれていない ([[Call などのプロパティの場合]) と理解できます。 ]]、[[Construct]] メソッド)。ステップ6では、前述のオブジェクト作成処理に従って新しいオブジェクトを作成し、その[[プロトタイプ]]などを設定します。
上記の処理手順からわかるように、関数を定義するときは常に、そのプロトタイプは Object インスタンスであるため、カスタム関数のインスタンス オブジェクトを作成するとき、デフォルトでは、そのプロトタイプ チェーンは Object.prototype を指します。
このオブジェクト モデル図には多くのものが含まれており、多くの箇所を注意深く理解する必要があるため、検証用のテスト コードを作成できます。この図を完全に理解すると、JavaScript 言語の理解もほぼ同じになります。以下に追加の手順を示します。
1. 図内には、組み込み関数コンストラクターが記載されている場所がいくつかあります。これは同じオブジェクトであり、テストおよび検証できます。
//FF2.0、IE7、Opera9.25、Safari3.0.4 で渡されます
Function==Function.constructor / /result: true
Function==Function.prototype.constructor //result: true
Function==Object.constructor //result: true
//関数もNumber.constructor、String.constructor、Array.constructor、RegExp.constructor などに相当します。
function fn(){}
Function==fn.constructor //result: true これはいくつかの問題を示しています。 関数ポイントシステムの組み込み関数コンストラクター (組み込み関数コンストラクター)。関数はブートストラップされます。システム内のすべての関数は関数から構築されます。
2. 左下隅の obj1、obj2...objn スコープは、次のようなコードで作成されたオブジェクトを参照します。
これらのオブジェクトは、ローカル コンストラクター メソッドがありますが、プロトタイプ チェーンから継承されたコンストラクター メソッド、つまり fn.prototype.constructor を取得します。関数オブジェクトの構築プロセスから、それが fn 自体であることがわかります。
右下隅の obj1、obj2...objn スコープは、次のようなコードで作成されたオブジェクトを参照します: var obj1=new Object(); または var obj1=new Number(123); ; または obj1=/w /; など。したがって、これらのオブジェクトのプロトタイプ チェーンのポイントと、プロトタイプ チェーンから継承されたコンストラクターの値 (コンストラクターが組み込みの Number コンストラクターであるか、組み込みの Object コンストラクターであるかなどを参照) は、特定のオブジェクトによって異なります。オブジェクトタイプ。また、var obj=new Object(123); この方法で作成されたオブジェクトのタイプは依然として Number であり、これもパラメータ値のタイプに基づいて決定する必要があることに注意してください。
同様に、ローカル コンストラクターはありませんが、プロトタイプ チェーンから継承されたコンストラクター メソッド、つまり組み込み *** コンストラクターを取得します。特定のコンストラクターはデータ型によって決まります。
3. 図のプロトタイプ チェーンに関する追加説明:
Object.prototype はチェーン全体の終点であり、その内部の [[Prototype]] は null です。
すべての関数のプロトタイプ チェーンは Function.prototype を指します。
関数のプロトタイプ チェーンは Function.prototype を指します。これは、設計者が関数をブートストラップされるように設計したため、仕様で必須です。 Function プロトタイプ チェーンがこの方法で設計された後は、Function.constructor==Function と Function instanceOf Function が両方とも true になります。さらに、Function はすでにトップレベルのコンストラクターですが、Function 自体も関数オブジェクトであり、何かによって作成される必要があるため、ブートストラップは意味的に合理的です。
Function.prototype のプロトタイプ チェーンは Object.prototype を指しますが、これも仕様で義務付けられています。まず、Function.prototype は Function のインスタンス オブジェクトです (typeof Function.prototype はそれが Function であることを知ることができますが、instanceOf は内部で追加で Prototype チェーンを設定しているためテストを通過できません)。そのため、Prototype の規則に従って、 Function.prototype の内部関数 [ [Prototype]] 値は Function.prototype オブジェクトである必要があります。つまり、その Prototype チェーンはそれ自体を指します。これにより、プロトタイプ チェーンに無限ループが作成される一方で、それ自体がエンドポイントになり、その結果、すべての関数オブジェクトが Object から派生しなくなります。この必須要件を追加すると、プロトタイプ チェーンのエンドポイントは 1 つだけになります。
4. Function.prototype は関数オブジェクトであるため、表示されるプロトタイプ属性、つまり Function.prototype.prototype を持つ必要がありますが、これは FireFox でのみアクセスでき、IE、Opera、またはサファリ。したがって、絵の中には存在しないことを示す記号が使われています。
5. デフォルトでは、ユーザー定義関数の [[Prototype]] 値は Object.prototype です。つまり、その暗黙のプロトタイプ チェーンは Object.prototype を指すため、図に示されています。ただし、これが常に当てはまるわけではありません。ユーザーがカスタム関数のプロトタイプ属性を設定する場合は状況が異なります。
実行モデル
実行コンテキストの概要
実行コンテキストは、JavaScript コードが実行される場所に存在し、JavaScript の実行範囲と期間処理などを完了するために使用される概念とメカニズムです。実行コンテキストには、変数オブジェクト、変数の初期化、スコープ/スコープ チェーンなどの概念が含まれます。異なるシナリオ/実行環境での処理にはいくつかの違いがあります。これらのシナリオについては、以下で説明します。
関数オブジェクトは、ユーザー定義関数オブジェクトとシステム組み込み関数オブジェクトに分けられ、ユーザー定義関数オブジェクトは以下の仕組みに従って処理されますが、組み込み関数オブジェクトは特定の実装に関連します。コンテキストの処理に関する要件はありません。つまり、コンテキストは一般的にこのセクションで説明する内容には適していません。
実行される JavaScript コードは 3 つのタイプに分けられ、これら 3 つのタイプの処理の違いについては後で説明します。
1. グローバル コード、つまり、どの関数にも含まれていないグローバル コード。 js ファイル、HTML ページに埋め込まれた js コードなど。
2. Eval コード。eval() 関数を使用して動的に実行される JS コードです。
3. 関数コード。ユーザー定義関数内の関数本体の JS コードです。
基本原則
ユーザー定義関数では、関数内でパラメーターを渡し、ローカル変数を定義できます。関数本体のコードでは、これらのパラメーターとローカル変数を使用できます。その背後にあるメカニズムは何ですか?
JS 実行フローが関数に入ると、JavaScript エンジンは変数オブジェクトと呼ばれるオブジェクトを内部的に作成します。関数の各パラメータに対応して、変数オブジェクトに属性を追加します。属性の名前と値は、パラメータの名前と値と同じです。関数内で変数が宣言されるたびに、その名前が変数オブジェクトに追加されます。そのため、変数に値を割り当てることは、変数オブジェクトの対応するプロパティに値を割り当てることを意味します。関数内のパラメーターまたはローカル変数にアクセスすると、変数 Object で対応するプロパティが検索され、その値が返されます。
一般に、変数オブジェクトは内部オブジェクトであり、JS コードで直接アクセスすることはできません。仕様では実装が必須ではないため、エンジン内の単なるデータ構造である可能性があります。
大まかに説明すると、スコープの概念は単純ではありません。たとえば、関数本体でグローバル変数を使用したり、関数をネストして定義したりすると、状況はさらに複雑になります。 。こうした状況にどう対処すればよいでしょうか? JavaScript エンジンは、ルールに従ってさまざまな実行位置に変数オブジェクトのリンク リストを作成します。変数にアクセスするときは、まずリンク リスト内の最初の変数オブジェクトを検索します。見つからない場合は、2 番目の変数の検索を続けます。検索が完了するまでオブジェクトを保持します。これがスコープ/スコープチェーンの一般的な概念です。
以下は各側面の詳細な処理です。
グローバル オブジェクト
JavaScript 実行環境には、HTML のウィンドウ オブジェクトなど、一意のグローバル オブジェクトであるグローバル オブジェクトが必要です。グローバル オブジェクトはホスト オブジェクトであり、JavaScript ランタイムのグローバル コンテナとしての役割に加えて、ECMA 仕様には追加の要件はありません。これには、Math、String、Date、parseInt および JavaScript のその他の組み込みグローバル オブジェクトと関数 (すべてグローバル オブジェクトの属性として) が含まれており、他のホスト環境で必要ないくつかの属性を含めることもできます。
変数オブジェクト
変数オブジェクトの基本概念は上で簡単に説明しました。変数オブジェクトを作成し、パラメーターとローカル変数を変数オブジェクトのプロパティに設定するプロセスは、変数の初期化と呼ばれます。これについては、スコープ チェーンと併せて後で詳しく説明します。
グローバル コード
変数オブジェクトはグローバル オブジェクトです。これが変数オブジェクトの唯一の特別な点です (アクセスできない内部オブジェクトであるという事実を指します)。
var globalVariable = "WWW";
document.write(window.globalVariable); //結果: WWW 上記のコードは、変数 globalVariable が定義されている場合、グローバル コード モードで実行されます。 、この属性をグローバル オブジェクト (つまり、ウィンドウ) オブジェクトに追加するため、出力は値 WWW になります。
ファンクションコード
変数オブジェクトはアクティベーションオブジェクトとも呼ばれます (いくつかの違いがあるため、違いを示すために仕様では新しい名前が付けられています。グローバルコード/評価コードでは変数オブジェクトと呼ばれます) 、関数コードでは変数オブジェクトと呼ばれます)。
関数の実行に入るたびに、新しいアクティベーション オブジェクト オブジェクトが作成され、次に引数オブジェクトが作成されてアクティベーション オブジェクトのプロパティとして設定され、変数のインスタンス化が処理されます。
関数を終了すると、アクティベーション オブジェクトは破棄されます (メモリ解放ではありませんが、ガベージ コレクションされる可能性があります)。
引数オブジェクトの属性:
長さ: 渡されるパラメータの実際の数です。関数オブジェクトの作成プロセスを参照すると、関数オブジェクトの長さは関数の定義時に必要なパラメーターの数です。
callee: は実行される関数オブジェクト自体です。その目的は、たとえば再帰呼び出しが必要な場合に、関数オブジェクトが自身を参照できるようにすることです。
function fnName(...) { ... } はこの方法で関数を定義し、その再帰呼び出しは関数本体で fnName を使用して完了できます。 var fn=function(...) { ... } この方法で匿名関数を定義します。関数本体で名前を使用して自分自身を参照することはできません。再帰呼び出しを実装するには、arguments.callee を通じて自分自身を参照できます。
パラメータ リスト: 呼び出し元によって実際に渡されるパラメータ リスト。このパラメータ リストは、インデックスを使用して実際のパラメータにアクセスする方法を提供します。関数の宣言時に指定されたパラメーター リストがある場合、変数のインスタンス化では、処理中にプロパティがアクティベーション オブジェクト オブジェクトに追加されます。関数宣言でパラメーター リストが指定されていない場合、または実際のパラメーターの数が関数宣言のパラメーターの数と異なる場合は、引数を介して各パラメーターにアクセスできます。
引数のパラメータ リストとアクティベーション オブジェクトのパラメータ属性は、同じパラメータ オブジェクトを参照します (変更された場合、両方の場所に反映されます)。仕様では、引数が配列オブジェクトである必要はありません。次にテストを示します。
//FF2.0、IE7、Opera9.25、Safari3.0.4 で渡されます
var argumentLike = { 0: "aaa", 1: 222, 2: "WWW", length: 3、呼び出し先: function () { } };
document.write(argumentsLike[2] "
"); //結果: WWW
document.write(argumentsLike[1] "<) ;br /> "); //結果: 222
//引数プロパティの場合と同様に、argumentsLike を Array オブジェクトに変換します。
var array = [].slice.apply(argumentsLike );
document.write(array instanceof Array); //結果: true
document.write("
"); ("|") ); //結果: WWW|222|aaa
Eval コード
変数オブジェクトは、eval が呼び出されたときの現在の実行コンテキストの変数オブジェクトです。 eval 関数がグローバル コードで呼び出される場合、その変数オブジェクトはグローバル オブジェクトとなり、関数内で eval が呼び出される場合、その変数オブジェクトは関数のアクティブ化オブジェクトになります。
//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("関数の引数");
出力結果は次のとおりです。
関数の引数
関数の変数
eval の変数
説明: 関数 fn のパラメーターとローカル変数は、定義された eval ローカル変数でアクセスできます。 in eval 変数オブジェクトは同じオブジェクトであるため、関数 fn からもアクセスできます。
スコープ/スコープチェーン
まず、スコープチェーンは連結リスト/スタックに似た構造であり、その中の各要素は基本的に変数オブジェクト/アクティブ化オブジェクトです。
第二に、実行コンテキストがあるところには必ず現在のスコープ チェーンが存在します。スコープ チェーンは実行コンテキストの特定の表現であると理解できます。
グローバル コード
スコープ チェーンには、グローバル オブジェクトというオブジェクトが 1 つだけ含まれています。 JavaScript コードの実行を開始する前に、エンジンはこのスコープ チェーン構造を作成します。
関数コード
関数オブジェクトには内部 [[Scope]] 属性があり、関数が配置されているスコープ チェーンを記録するために使用されます。
関数オブジェクトを作成するとき、エンジンは現在の実行環境のスコープ チェーンを関数の [[Construct]] メソッドに渡します。 [[Construct]] は、渡されたスコープ チェーンと同じ内容を持つ新しいスコープ チェーンを作成し、それを作成された関数の内部 [[Scope]] 属性に割り当てます。関数オブジェクトの作成プロセスに関する前のセクションでは、このプロセスはステップ 4 と 5 の間にありました。
関数呼び出しを開始すると、同じ関数の再帰呼び出しを含む新しいスコープ チェーンも作成され、関数を終了するときにこのスコープ チェーンは破棄されます。新しく作成されたスコープ チェーンの最初のオブジェクトはアクティベーション オブジェクトで、次の内容は内部の [[Scope]] に格納されているスコープ チェーンの内容とまったく同じです。
評価コード
実行のために評価コードを入力すると、新しいスコープ チェーンが作成されます。その内容は、現在の実行コンテキストのスコープ チェーンとまったく同じです。
例の説明
スコープ チェーンの原理は上記のとおりです。上記の動作を理解するには、JS コードの実行と変数のインスタンス化の詳細を組み合わせる必要があります。以下で包括的に説明します。以下が JavaScript グローバル コードの一部であると仮定します:
var innerVar1= "グローバル コードの変数";
function fn1(arg1, arg2){
var innerVar1="関数コードの変数";
function fn2() { return innerVar1 " - " innerVar1 " - " " - " (arg1 arg2); }
return fn2();
}
var externalVar2=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に代入します。
他の場合でも、スコープチェーンと変数のインスタンス化は、上記のプロセスと同様に分析できます。
上記の例によれば、次のテスト コードの結果を説明できます。
//FF2.0、IE7、Opera9.25、Safari3.0.4 で渡されます
function fn(obj){
return {
/ /obj にローカル変数 "outerVar" が存在するかどうかをテストします
exists: Object.prototype.hasOwnProperty.call(obj, "outerVar"),
//変数 "outerVar" の値をテストします
value : obj.outerVar
};
var result1 = fn(ウィンドウ);
var result2 = fn(ウィンドウ); >document.write( result1.exists " " result1.value); //result: true 未定義
document.write("
");
document.write(result2.exists " " result2.value); //result: true WWWresult1 が呼び出された場合、outerVar 宣言と代入ステートメントは実行されていませんが、テスト結果ウィンドウ オブジェクトにはすでにローカル プロパティ externalVar があり、その値は未定義です。 result2 の externalVar には値が割り当てられているため、window.outerVar の値はすでに存在します。実際に使用する場合は、使用してから定義しないと、仕様書に記載されていないメーカーごとの実装方法に矛盾が生じるため、問題が発生する場合があります。
특수 처리
1.(obj) { ... }를 사용하여 이 구문을 구현하는 것은 obj 객체를 현재 범위 체인 앞에 삽입하여 obj가 먼저 검색되는지 확인하는 것입니다. 해당 이름을 가진 속성이 존재합니다. 다른 유사한 것에는 catch 문이 포함됩니다.
2. 이전의 인수 개체에 대한 자세한 설명에서 재귀 함수 호출 지원에 대해 언급했습니다. 위의 내용은 스코프 체인의 작동 원리로 인해 아직 이 현상을 설명할 수 없습니다. 여기에는 특별한 처리가 있기 때문입니다.
이름이 지정된 함수 개체가 생성될 때마다 JavaScript 엔진은 현재 실행 컨텍스트 범위 체인 앞에 개체를 삽입합니다. 이 개체는 새 Object() 메서드를 사용하여 생성되고 범위 체인이 전달됩니다. 함수 생성자 [ [Construct]], 최종 생성된 함수 개체는 [[Scope]] 내부에 이 개체 개체를 포함합니다. 생성 프로세스가 반환된 후 JavaScript 엔진은 함수 이름과 반환된 함수 개체의 값을 사용하여 개체에 속성을 추가한 다음 현재 실행 컨텍스트의 범위 체인에서 이를 제거합니다. 이런 식으로 함수 객체의 범위 체인의 첫 번째 객체는 자신에 대한 참조이며 제거 작업은 함수 객체가 생성된 범위 체인의 복원을 보장합니다.
이 키워드 처리
실행 컨텍스트에 포함된 또 다른 개념은 this 키워드입니다.
글로벌 코드의 this 키워드는 전역 개체입니다. 함수가 호출될 때 this 키워드는 호출자입니다(예: obj1.fn1()). fn1에서 this 개체는 평가 코드의 this 키워드입니다. 현재 실행 컨텍스트 개체의 변수입니다.
함수를 호출할 때 JavaScript는 사용자가 이 키워드의 값, 즉 각 함수가 갖는 호출 및 적용 메서드를 지정할 수 있는 기회를 제공합니다. 예:
fn1.call(obj1, arg1, arg2, ...) 또는 fn1.apply(obj1, argArray)는 모두 obj1을 이 키워드로 사용하여 fn1 함수를 호출하고 실행하며 모든 후속 매개변수는 다음과 같이 사용됩니다. 함수 fn1 매개변수. obj1이 null이거나 정의되지 않은 경우 전역 개체가 이 키워드의 값으로 사용되며, obj1이 개체 유형이 아닌 경우 개체 유형으로 변환됩니다. 유일한 차이점은 Apply를 사용하면 각 매개변수를 배열 형식으로 제공할 수 있는 반면, 호출 메소드는 매개변수를 하나씩 제공해야 한다는 것입니다.
이 방법은 이전 테스트 샘플 코드의 여러 곳에서 사용되었습니다. 예를 들어 window 객체에는 hasOwnProperty 메서드가 없습니다. 또한 Object.prototype.hasOwnProperty.call(window, "propertyName")을 사용하여 로컬 속성이 있는지 테스트할 수도 있습니다.
JavaScript의 클로저
예:
//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달됨
function external(){
var a="aaa"
var b="bbb";
return function(){ return a " " b;
}
var inner=outer();
document.write(inner());outer는 인라인 함수를 반환합니다. 함수는 외부의 지역 변수 a와 b를 사용합니다. 논리적으로 말하면, 외부의 지역 변수는 반환될 때 범위를 벗어나므로 inner() 호출을 사용할 수 없습니다. 이것이 클로저입니다. 즉, 함수 호출이 포함된 함수를 반환하고, 포함된 함수는 닫혀야 하는 외부 함수의 지역 변수, 매개변수 및 기타 리소스를 참조합니다(Close).
스코프 체인에 대한 이전 이해에 따르면 반환된 인라인 함수는 생성 당시 이미 스코프 체인을 보유하고 있다고 설명할 수 있습니다. 비록 외부 반환으로 인해 이러한 개체가 범위 및 수명 범위를 초과하게 됩니다. , JavaScript는 자동 가비지 수집을 사용하여 객체 메모리를 확보합니다. 규칙에 따라 주기적으로 확인되며 참조가 없는 경우에만 객체가 해제됩니다. 따라서 위의 코드는 올바르게 실행됩니다.