成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

徹底理解Javascript中的作用域鏈

zhunjiee / 627人閱讀

摘要:全局和上下文中的作用域鏈這里不一定很有趣,但必須要提示一下。全局上下文的作用域鏈僅包含全局對象。代碼的上下文與當前的調用上下文擁有同樣的作用域鏈。代碼執(zhí)行時對作用域鏈的影響在中,在代碼執(zhí)行階段有兩個聲明能修改作用域鏈。

1 定義

我們已經(jīng)知道一個執(zhí)行上下文中的數(shù)據(jù)(參數(shù),變量,函數(shù))作為屬性存儲在變量對象中。

也知道變量對象是在每次進入上下文是創(chuàng)建并填入初始值,值的更新出現(xiàn)在代碼執(zhí)行階段。

作用域鏈就是這些變量對象的鏈表。

讓我們看一下和作用域相關的上下文結構
VO是當前上下文的變量對象,重點是Scope屬性,Scope = VO+[[scope]]。其中[[scope]]為所有父上下文變量對象的鏈表。

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

函數(shù)的生命周期分為創(chuàng)建和激活。

2 函數(shù)創(chuàng)建階段
var x = 10;
  
function foo() {
  var y = 20;
  alert(x + y);
}
  
foo(); // 30

此前,我們僅僅談到有關當前上下文的變量對象。這里,我們看到變量“y”在函數(shù)“foo”中定義(意味著它在foo上下文的AO中),但是變量“x”并未在“foo”上下文中定義,相應地,它也不會添加到“foo”的AO中。乍一看,變量“x”相對于函數(shù)“foo”根本就不存在;但正如我們在下面看到的——也僅僅是“一瞥”,我們發(fā)現(xiàn),“foo”上下文的活動對象中僅包含一個屬性--“y”。

fooContext.AO = {
y: undefined // undefined – 進入上下文的時候是20 – at activation
};

函數(shù)“foo”如何訪問到變量“x”?理論上函數(shù)應該能訪問一個更高一層上下文的變量對象。實際上它正是這樣,這種機制是通過函數(shù)內部的[[scope]]屬性來實現(xiàn)的。

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

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

3 函數(shù)激活階段

正如在定義中說到的,進入上下文創(chuàng)建AO/VO之后,上下文的Scope屬性(變量查找的一個作用域鏈)作如下定義:

Scope = AO|VO + [[Scope]]

上面代碼的意思是:活動對象是作用域數(shù)組的第一個對象,即添加到作用域的前端。
Scope = [AO].concat([[Scope]]);

這個特點對于標示符解析的處理來說很重要。

標示符解析是一個處理過程,用來確定一個變量(或函數(shù)聲明)屬于哪個變量對象。
標識符解析過程包含與變量名對應屬性的查找,即作用域中變量對象的連續(xù)查找,從最深的上下文開始,繞過作用域鏈直到最上層。

這樣一來,在向上查找中,一個上下文中的局部變量較之于父作用域的變量擁有較高的優(yōu)先級。萬一兩個變量有相同的名稱但來自不同的作用域,那么第一個被發(fā)現(xiàn)的是在最深作用域中。

4 閉包

在ECMAScript中,閉包與函數(shù)的[[scope]]直接相關,正如我們提到的那樣,[[scope]]在函數(shù)創(chuàng)建時被存儲,與函數(shù)共存亡。實際上,閉包是函數(shù)代碼和其[[scope]]的結合。

因為閉包函數(shù)在創(chuàng)建的時候就創(chuàng)建了父級的變量對象鏈表,也就是父級作用域鏈, 然后閉包函數(shù)再訪問父級作用域鏈中的變量,導致父級函數(shù)執(zhí)行完畢后仍然不能釋放執(zhí)行上下文的情況。

5 通過構造函數(shù)創(chuàng)建的函數(shù)的[[scope]]

在上面的例子中,我們看到,在函數(shù)創(chuàng)建時獲得函數(shù)的[[scope]]屬性,通過該屬性訪問到所有父上下文的變量。但是,這個規(guī)則有一個重要的例外,它涉及到通過函數(shù)構造函數(shù)創(chuàng)建的函數(shù)。

var x = 10;
  
function foo() {
  
 var y = 20;
  
 function barFD() { // 函數(shù)聲明
alert(x);
alert(y);
}
  
 var barFE = function () { // 函數(shù)表達式
alert(x);
alert(y);
};
  
 var barFn = Function("alert(x); alert(y);");
  
barFD(); // 10, 20
barFE(); // 10, 20
barFn(); // 10, "y" is not defined
  
}
  
foo();

我們看到,通過函數(shù)構造函數(shù)(Function constructor)創(chuàng)建的函數(shù)“bar”,是不能訪問變量“y”的。但這并不意味著函數(shù)“barFn”沒有[[scope]]屬性(否則它不能訪問到變量“x”)。問題在于通過函構造函數(shù)創(chuàng)建的函數(shù)的[[scope]]屬性總是唯一的全局對象??紤]到這一點,如通過這種函數(shù)創(chuàng)建除全局之外的最上層的上下文閉包是不可能的。

6 全局和eval上下文中的作用域鏈

這里不一定很有趣,但必須要提示一下。全局上下文的作用域鏈僅包含全局對象。代碼eval的上下文與當前的調用上下文(calling context)擁有同樣的作用域鏈。

globalContext.Scope = [
Global
];
  
evalContext.Scope === callingContext.Scope;
7 代碼執(zhí)行時對作用域鏈的影響

在ECMAScript 中,在代碼執(zhí)行階段有兩個聲明能修改作用域鏈。這就是with聲明和catch語句。它們添加到作用域鏈的最前端,對象須在這些聲明中出現(xiàn)的標識符中查找。如果發(fā)生其中的一個,作用域鏈簡要的作如下修改:

Scope = withObject|catchObject + AO|VO + [[Scope]]

eval代碼運行的字符串利用當前調用的上下文,并且能夠修改當前上下文中的變量對象,也就是說eval內和eval外的代碼一樣,只是不能變量提升,執(zhí)行起來是一樣的。
with代碼塊和catch代碼塊都改變了作用域鏈,但是在他們代碼塊中聲明的變量,也存在了函數(shù)作用域中,只是with的對象和catch對象外部不能訪問而已。

eval("var x=3");
console.log(x); //3      
with (obj1) {
    var innner ="inner";
    console.log(a); //1
    console.log(b); //2
}
console.log(innner); // inner 仍能訪問
console.log(a) //訪問不到
try {
    throw new Error("error")
}
catch (e) {
    var cat = 2;
}
console.log(cat); //2 仍能訪問

英文原文:http://dmitrysoshnikov.com/ec...
本文絕大部分內容來自上述地址,僅做少許修改

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

轉載請注明本文地址:http://systransis.cn/yun/86609.html

相關文章

  • 徹底明白作用域、執(zhí)行上下文

    摘要:代碼執(zhí)行階段在這個階段會生成三個重要的東西變量對象,作用域鏈變量對象在函數(shù)上下文中,我們用活動對象來表示變量對象。這時候執(zhí)行上下文的作用域鏈,我們命名為至此,作用域鏈創(chuàng)建完畢。 好久沒更新文章了,這一憋就是一個大的。說起js中的概念,執(zhí)行上下文和作用域應該是大家最容易混淆的,你說混淆就混淆吧,其實大多數(shù)人在開發(fā)的時候不是很關注這兩個名詞,但是這里面偏偏還夾雜好多其他的概念--變量提升啊...

    whataa 評論0 收藏0
  • 前端基礎進階(四):詳細圖解作用域鏈與閉包

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

    aikin 評論0 收藏0
  • JavaScript之例題中徹底理解this

    摘要:最后重點理解結論箭頭函數(shù)的,總是指向定義時所在的對象,而不是運行時所在的對象。輸出,箭頭函數(shù)不會綁定所以傳入指向無效。原因是,要徹底理解應該是建立在已經(jīng)大致理解了中的執(zhí)行上下文,作用域作用域鏈,閉包,變量對象,函數(shù)執(zhí)行過程的基礎上。 本文共 2025 字,看完只需 8 分鐘 概述 前面的文章講解了 JavaScript 中的執(zhí)行上下文,作用域,變量對象,this 的相關原理,但是我...

    Hwg 評論0 收藏0
  • 初學者徹底理解javascript閉包以及this關鍵字

    摘要:理解了這句話,我們就可以來看閉包了閉包前面說過,函數(shù)可以訪問函數(shù)作用域鏈中的變量,但如果我們想在函數(shù)外訪問函數(shù)內卻不行了。 不管是閉包還是this關鍵字,都是困擾JS初學者的比較難懂的東西,如果你對它們的認識還不足夠清晰,那么現(xiàn)在就一起把它們掌握掉。還是那句話,我們從最基本的開始,建立起一個非常清晰的知識結構,好了,開始吧 ? 閉包 當然我們今天說的是javascript里的閉包。要學...

    魏明 評論0 收藏0
  • Javascript】深入理解this作用域問題以及new/let/var/const對this作

    摘要:理解作用域高級程序設計中有說到對象是在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的在全局函數(shù)中,等于,而當函數(shù)被作為某個對象調用時,等于那個對象。指向與匿名函數(shù)沒有關系如果函數(shù)獨立調用,那么該函數(shù)內部的,則指向。 理解this作用域 《javascript高級程序設計》中有說到: this對象是在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的:在全局函數(shù)中,this等于window,而當函數(shù)被作為某個對象調用時,t...

    snowLu 評論0 收藏0

發(fā)表評論

0條評論

zhunjiee

|高級講師

TA的文章

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