国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

變量對象+作用域鏈+閉包

Yangder / 1758人閱讀

摘要:傳入值現(xiàn)在結(jié)果是正確的了創(chuàng)建了一個匿名函數(shù),通過把變量作為參數(shù)傳進(jìn)去,這樣在執(zhí)行的時候,由于內(nèi)部的形參能夠訪問到變量,所以無需到父級作用域鏈上進(jìn)行尋找,因此最后輸出達(dá)到預(yù)期目的。

下文根據(jù)湯姆大叔的深入javascript系列文章刪改,如果想深入理解請閱讀湯姆大叔的系列文章。
http://www.cnblogs.com/TomXu/...

變量對象 初步介紹
變量對象(縮寫為VO)是一個與執(zhí)行上下文相關(guān)的特殊對象,它存儲著在上下文中聲明的以下內(nèi)容:
    變量 (var, 變量聲明);
    函數(shù)聲明 (FunctionDeclaration, 縮寫為FD);
    函數(shù)的形參
    

我們可以用普通的ECMAScript對象來表示一個變量對象:

VO = {};

VO是執(zhí)行上下文的屬性(property),所以:

activeExecutionContext = {
  VO: {
    // 上下文數(shù)據(jù)(var, FD, function arguments)
  }
};

只有全局上下文的變量對象允許通過VO的屬性名稱來間接訪問(因為在全局上下文里,全局對象自身就是變量對象),在其它上下文中是不能直接訪問VO對象的,因為它只是內(nèi)部機(jī)制的一個實現(xiàn)。

全局上下文中的變量對象

只有全局上下文的變量對象允許通過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]); // 間接通過動態(tài)屬性名稱訪問:"test"
函數(shù)上下文中的變量對象

在函數(shù)執(zhí)行上下文中,VO是不能直接訪問的,此時由活動對象(activation object,縮寫為AO)扮演VO的角色。

VO(functionContext) === AO;

在理解函數(shù)上下文中的變量對象時,我們通過處理上下文代碼的2個階段來進(jìn)行理解

1.進(jìn)入執(zhí)行上下文
2.執(zhí)行代碼
進(jìn)入執(zhí)行上下文

進(jìn)入執(zhí)行上文文的時候,也即是代碼執(zhí)行之前,此時VO包含了下列屬性

函數(shù)形參
函數(shù)聲明
變量聲明

其中,函數(shù)聲明的等級最高,然后是函數(shù)形參,最后才是變量聲明。越高等級的聲明可以覆蓋低等級的聲明。

執(zhí)行代碼

這個周期內(nèi),AO/VO已經(jīng)擁有了屬性(不過,并不是所有的屬性都有值,大部分屬性的值還是系統(tǒng)默認(rèn)的初始值undefined )。這個時候會進(jìn)行賦值操作以及執(zhí)行代碼。

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

在進(jìn)入上下文階段,由于函數(shù)具有最高的級別,所以第一次alert(x)輸出的是函數(shù)。之后進(jìn)行變量賦值,分別alert 10 20。

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

由于形參聲明比變量聲明級別高,所以alert(3),因為在進(jìn)入執(zhí)行上下文時變量無法覆蓋形參聲明,所以輸出的是3而不是undefined。

不使用var可以聲明一個全局變量,這句話是錯誤的。
alert(a); // undefined
alert(b); // "b" 沒有聲明,報錯
 
b = 10;
var a = 20;
作用域鏈

函數(shù)上下文的作用域鏈在函數(shù)調(diào)用時創(chuàng)建的,包含活動對象和這個函數(shù)內(nèi)部的[[scope]]屬性。函數(shù)上下文包括以下內(nèi)容:

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

其scope定義如下:

Scope = AO + [[Scope]]

[[scope]]是所有父變量對象的層級鏈,處于當(dāng)前函數(shù)上下文之上,在函數(shù)創(chuàng)建時存于其中。

注意這重要的一點(diǎn)--[[scope]]在函數(shù)創(chuàng)建時被存儲--靜態(tài)(不變的),永遠(yuǎn)永遠(yuǎn),直至函數(shù)銷毀。即:函數(shù)可以永不調(diào)用,但[[scope]]屬性已經(jīng)寫入,并存儲在函數(shù)對象中。

另外一個需要考慮的是--與作用域鏈對比,[[scope]]是函數(shù)的一個屬性而不是上下文。

因此我個人的理解是作用域鏈應(yīng)該是函數(shù)本身的活動對象+父級的變量對象。其中函數(shù)本身的活動對象總是排在第一位,在尋找標(biāo)識符的時候,如果在當(dāng)前活動對象找不到,那么會遍歷作用域鏈上的父級變量對象。其中[[scope]]在函數(shù)創(chuàng)建時被存儲,與函數(shù)共存亡。

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

說明函數(shù)的作用域鏈在函數(shù)創(chuàng)建的時候就已經(jīng)定義好了,是靜態(tài)的,不因為調(diào)用的時候而改變。

閉包 作用域鏈的加深理解
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兩個函數(shù)創(chuàng)建的時候,內(nèi)部的變量x都是從父級函數(shù)foo的變量對象x中引用,所以其實兩個函數(shù)都是共享一個作用域,因此導(dǎo)致x變量共通了。

經(jīng)典閉包
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

解釋跟上面類似。function在創(chuàng)建的時候,內(nèi)部的變量k通過訪問作用域鏈即是父級的變量對象k拿到,而當(dāng)函數(shù)被調(diào)用的時候,for循環(huán)早已執(zhí)行完畢,此時的K是3,所以三個函數(shù)調(diào)用的時候輸出的值都為3。

var data = [];

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

// 現(xiàn)在結(jié)果是正確的了
data[0](); // 0
data[1](); // 1
data[2](); // 2

創(chuàng)建了一個匿名函數(shù),通過把k變量作為參數(shù)傳進(jìn)去,這樣在執(zhí)行function的時候,由于內(nèi)部的形參能夠訪問到k變量,所以無需到父級作用域鏈上進(jìn)行尋找,因此最后輸出達(dá)到預(yù)期目的。

閉包的理論定義

這里說明一下,開發(fā)人員經(jīng)常錯誤將閉包簡化理解成從父上下文中返回內(nèi)部函數(shù),甚至理解成只有匿名函數(shù)才能是閉包。

ECMAScript中,閉包指的是:

1.從理論角度:所有的函數(shù)。因為它們都在創(chuàng)建的時候就將上層上下文的數(shù)據(jù)保存起來了。哪怕是簡單的全局變量也是如此,因為函數(shù)中訪問全局變量就相當(dāng)于是在訪問自由變量,這個時候使用最外層的作用域。

2.從實踐角度:以下函數(shù)才算是閉包:
    1.即使創(chuàng)建它的上下文已經(jīng)銷毀,它仍然存在(比如,內(nèi)部函數(shù)從父函數(shù)中返回)
    2.在代碼中引用了自由變量

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86818.html

相關(guān)文章

  • 前端基礎(chǔ)進(jìn)階(四):詳細(xì)圖解作用域鏈閉包

    摘要:之前一篇文章我們詳細(xì)說明了變量對象,而這里,我們將詳細(xì)說明作用域鏈。而的作用域鏈,則同時包含了這三個變量對象,所以的執(zhí)行上下文可如下表示。下圖展示了閉包的作用域鏈。其中為當(dāng)前的函數(shù)調(diào)用棧,為當(dāng)前正在被執(zhí)行的函數(shù)的作用域鏈,為當(dāng)前的局部變量。 showImg(https://segmentfault.com/img/remote/1460000008329355);初學(xué)JavaScrip...

    aikin 評論0 收藏0
  • 談js中的作用域鏈閉包

    摘要:所以,當(dāng)在函數(shù)中使用全局變量的時候,所產(chǎn)生的代價是最大的,因為全局對象一直處于作用域鏈的最末位置,讀取局部變量是最快的。 什么是作用域 在編程語言中,作用域控制著變量與參數(shù)的可見性及生命周期,它能減少名稱沖突,而且提供了自動內(nèi)存管理(javascript 語言精粹) 靜態(tài)作用域 再者,js不像其他的編程語言一樣,擁有著塊級作用域,就像下面一段代碼。 function afunction...

    LucasTwilight 評論0 收藏0
  • 還是不明白JavaScript - 執(zhí)行環(huán)境、作用域、作用域鏈閉包嗎?

    摘要:所以,全局執(zhí)行環(huán)境的變量對象始終都是作用域鏈中的最后一個對象。講到這里,可能你已經(jīng)對執(zhí)行環(huán)境執(zhí)行環(huán)境對象變量對象作用域作用域鏈的理解已經(jīng)他們之間的關(guān)系有了一個較清晰的認(rèn)識。 JavaScript中的執(zhí)行環(huán)境、作用域、作用域鏈、閉包一直是一個非常有意思的話題,很多博主和大神都分享過相關(guān)的文章。這些知識點(diǎn)不僅比較抽象,不易理解,更重要的是與這些知識點(diǎn)相關(guān)的問題在面試中高頻出現(xiàn)。之前我也看過...

    jlanglang 評論0 收藏0
  • [ JS 進(jìn)階 ] 閉包作用域鏈,垃圾回收,內(nèi)存泄露

    摘要:執(zhí)行返回的內(nèi)部函數(shù),依然能訪問變量輸出閉包中的作用域鏈理解作用域鏈對理解閉包也很有幫助。早期的版本里采用是計數(shù)的垃圾回收機(jī)制,閉包導(dǎo)致內(nèi)存泄露的一個原因就是這個算法的一個缺陷。 關(guān)于閉包,我翻了幾遍書,看了幾遍視頻,查了一些資料,可是還是迷迷糊糊的,干脆自己動手來個總結(jié)吧 !歡迎指正... (~ o ~)~zZ 1. 什么是閉包? 來看一些關(guān)于閉包的定義: 閉包是指有權(quán)...

    clasnake 評論0 收藏0
  • JS基礎(chǔ)知識:變量對象作用域鏈閉包

    摘要:前言這段時間一直在消化作用域鏈和閉包的相關(guān)知識。而作用域鏈則是這套規(guī)則這套規(guī)則的具體運(yùn)行。是變量對象的縮寫那這樣放有什么好處呢我們知道作用域鏈保證了當(dāng)前執(zhí)行環(huán)境對符合訪問權(quán)限的變量和函數(shù)的有序訪問。 前言:這段時間一直在消化作用域鏈和閉包的相關(guān)知識。之前看《JS高程》和一些技術(shù)博客,對于這些概念的論述多多少少不太清楚或者不太完整,包括一些大神的技術(shù)文章。這也給我的學(xué)習(xí)上造成了一些困惑,...

    Keven 評論0 收藏0
  • 溫故js系列(14)-閉包&垃圾回收&內(nèi)存泄露&閉包應(yīng)用&作用域鏈&

    摘要:該對象包含了函數(shù)的所有局部變量命名參數(shù)參數(shù)集合以及,然后此對象會被推入作用域鏈的前端。如果整個作用域鏈上都無法找到,則返回。此時的作用域鏈包含了兩個對象的活動對象和對象。 前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:閉包 JavaScript-閉包 閉包(closure)是一個讓人又愛又恨的somet...

    Amio 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<