+ +スコープ鎖可変オブジェクト閉鎖

以下は、アンクルトムシリーズの深い理解を読みたい場合は記事のjavascript切除のアンクルトムの綿密シリーズ、によります。
http://www.cnblogs.com/TomXu / ...

変数オブジェクト

初期導入


变量对象(缩写为VO)是一个与执行上下文相关的特殊对象,它存储着在上下文中声明的以下内容:
    变量 (var, 变量声明);
    函数声明 (FunctionDeclaration, 缩写为FD);
    函数的形参
    

私たちは、変数オブジェクトを表すために、通常のECMAScriptオブジェクトを使用することができます。

VO = {};

VOはそのため、プロパティ(プロパティ)実行コンテキストであります:

activeExecutionContext = {
  VO: {
    // 上下文数据(var, FD, function arguments)
  }
};

それは内部のメカニズムだけで実現だからグローバルな文脈の唯一の変数オブジェクトは、間接アクセスできますVOのプロパティ名によって(グローバル・コンテキストのように、グローバルオブジェクトそのものが変数オブジェクトである)、VOは、他のコンテキスト内のオブジェクトに直接アクセスすることはできません。

グローバルコンテキストの変数オブジェクト

VOは、間接的にアクセスするプロパティ名を許可するグローバルコンテキストの変数オブジェクトのみ

グローバルな文脈では、そこに

VO(globalContext) === global;

変数のオブジェクトが私たちを待っているのでグローバルな文脈で宣言されたグローバル変数があり、グローバル変数は、グローバルコンテキスト内のオブジェクトはグローバルオブジェクトそのものです。だから我々はを通じて名前VO間接的にアクセスすることができます属性

var a = new String('test');
 
alert(a); // 直接访问,在VO(globalContext)里找到:"test"
 
alert(window['a']); // 间接通过global访问:global === VO(globalContext): "test"
alert(a === this.a); // true
 
var aKey = 'a';
alert(window[aKey]); // 间接通过动态属性名称访问:"test"

変数オブジェクトの関数コンテキスト

関数の実装の文脈において、VOはVOの役割(AOと略記起動オブジェクト)アクティブオブジェクトによって今回、直接アクセスできない。

VO(functionContext) === AO;

可変オブジェクトコンテキストの機能を理解する上で、2段我々のプロセスコンテキストのコードと理解されるべき

1.进入执行上下文
2.执行代码

実行コンテキストに

コードが実行される前に、あるテキストに変換する上で実行する場合は、この時点では、以下のVO属性が含まれ

函数形参
函数声明
变量声明

その中でも、関数宣言、関数のパラメータ、および最終的には変数宣言の最高レベル。宣言のより高いレベルは、カバレッジの低レベルを宣言することができます。

コードの実行

この期間内に、AO / VOがすでに財産を持っている(ただし、すべてのプロパティの値は、または初期値は未定義システムのデフォルトのプロパティのほとんどの価値を持っていません)。この時間は、割り当てを行うと、コードを実行します。

alert(x); // function
 
var x = 10;
alert(x); // 10
 
x = 20;
 
function x() {};
 
alert(x); // 20

機能が最も高いレベルを有しているので入る相の文脈では、最初の警告(x)は、出力の関数です。変数への代入の後、彼らは警告10 20です。

function bar (x){
    alert(x);
    var x = 2;
}
bar(3); //3

宣言されたパラメータは、変数宣言のレベルよりも高いので、警告(3)は、カバーできない実行コンテキスト変数パラメータ文を入力するときのように、出力3は不定されません。

この文は間違っている、グローバル変数を宣言するためにVARを使用することはできません。

alert(a); // undefined
alert(b); // "b" 没有声明,报错
 
b = 10;
var a = 20;

スコープチェーン

関数コンテキストスコープチェーン関数が呼び出されたときに作成されたが、アクティブオブジェクトと内部[[範囲]]プロパティの機能を含んでいます。コンテキストには、以下の機能が含まれています。

activeExecutionContext = {
    VO: {...}, // or AO
    this: thisValue,
    Scope: [ // Scope chain
      // 所有变量对象的列表
      // for identifiers lookup
    ]
};

以下のように、どの範囲が定義されています。

Scope = AO + [[Scope]]

[スコープ]すべての階層鎖可変オブジェクトの親である、現在の関数コンテキストが記憶され、関数作成時に、上記あります。

これは重要なポイントであることに注意してください - 機能の破壊まで、永遠に、静的(不変) - [[スコープ]]機能の作成時には、保存されています。つまり:関数は呼び出すことはできませんが、[[スコープ]]プロパティは関数オブジェクトで記述され、保存されています。

スコープチェーン、[範囲]とは対照的に、代わりに、コンテキスト属性の関数である - 別の考慮事項は、ということです。

私は、スコープチェーンは、関数自体アクティブオブジェクト+親変数オブジェクトでなければならないことを理解するようにします。関数自体アクティブオブジェクトは常に識別子の時間のための検索で1位どこで現在アクティブなオブジェクトで見つからない場合、それはスコープチェーン上の親変数オブジェクトを横断します。前記[範囲]の関数作成滅びるでは記憶され、機能します。

var x = 10;
 
function foo() {
  alert(x);
}
 
(function () {
  var x = 20;
  foo(); // 10, but not 20
})();

関数が定義されて作成された説明スコープチェーン機能は、コールが変更されていないときので、静的です。

クロージャ

スコープチェーンの理解深めます

var firstClosure;
var secondClosure;

function foo() {

  var x = 1;

  firstClosure = function () { return ++x; };
  secondClosure = function () { return --x; };

  x = 2; // 影响 AO["x"], 在2个闭包公有的[[Scope]]中

  alert(firstClosure()); // 3, 通过第一个闭包的[[Scope]]
}

foo();

alert(firstClosure()); // 4
alert(secondClosure()); // 3

firstClosureとsecondClosure 2つの関数は内部変数xが関数foo内の親オブジェクトx変数から参照される作成すると、二つの機能は、このように、共通変数xにつながる、実際共有スコープです。

クラシッククロージャ

var data = [];

for (var k = 0; k < 3; k++) {
  data[k] = function () {
    alert(k);
  };
}

data[0](); // 3, 而不是0
data[1](); // 3, 而不是1
data[2](); // 3, 而不是2

同様に上記の説明です。それはループのために、関数が呼び出されたときに、親スコープチェーン変数kはオブジェクトを取得することで、内部変数kをアクセスすることによって、作成された関数は、3 Kが3である、この場合には、終了しましたときに、関数呼び出しの出力の値は3です。

var data = [];

for (var k = 0; k < 3; k++) {
  data[k] = (function _helper(x) {
    return function () {
      alert(x);
    };
  })(k); // 传入"k"值
}

// 现在结果是正确的了
data[0](); // 0
data[1](); // 1
data[2](); // 2

最終的な出力が達すると予想されるので、匿名関数を作成するので、内部パラメータkの関数の実装にアクセス可変することができるようにすることは、パラメータとしてスコープ鎖可変Kパスを通して見る親にする必要がありません目的。

クロージャー理論的な定義

開発者はしばしば誤って親コンテキストから閉鎖簡素化内部関数の戻り値として理解ここで説明するのは、唯一の無名関数も、クロージャとして理解することができます。

ECMAScriptのでは、閉鎖手段は次のとおりです。

1.从理论角度:所有的函数。因为它们都在创建的时候就将上层上下文的数据保存起来了。哪怕是简单的全局变量也是如此,因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域。

2.从实践角度:以下函数才算是闭包:
    1.即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)
    2.在代码中引用了自由变量

おすすめ

転載: www.cnblogs.com/jlfw/p/12536459.html