結合執行上下文理解js閉包、作用域及作用域鏈
阿新 • • 發佈:2020-08-19
一MDN
上的定義
- 函式和其對周圍狀態(詞法環境---作用域鏈)的引用捆綁在一起構成了閉包。
- 每當函式建立時,就會在函式生成時形成閉包。
- 內部函式可以訪問外部函式作用域
二、js中的作用域及作用域鏈---靜態作用域--詞法作用域--詞法環境
先來看一段幾乎都知道的白話文:作用域是變數和函式的可訪問範圍及生命週期。在當前作用域訪問變數,如果沒找到,就會去外層作用域查詢,一級級向上,直到最外層的window物件為止,這樣的層級關係便是作用域鏈。
在執行上下文中的體現:訪問變數、函式時,去當前執行上下文中的作用域鏈scope chain
中查詢,scope chain
的頂端為當前執行上下文的變數物件————對應著當前作用域。若沒有查詢到,則去外層變數物件中查詢,直到最外層的變數物件為止(即全域性作用域)。
引出下一個問題:執行上下文屬性中的scope chain
是怎麼建立的?
- 在函式定義建立時,會把其能訪問到的所有外層變數物件都儲存到函式的內部屬性
[[scope]]
中 - 建立執行上下文時,首先建立
scope chain
這個屬性,再把函式的內部屬性[[scope]]
複製到scope chain
中,但此時還並不是完整的作用域鏈,等到variable object
變數物件建立完後,新增到scope chain
的頂端,形成最終的作用域鏈。
得出重要結論:
- 在函式建立時,就已經儲存好了其所能訪問到的所有外層的變數集合————也就是白話文中的靜態作用域,即函式的作用域在定義時就已經確定了。
MDN
文件中閉包
翻譯成白話文:函式和其作用域鏈上的變數物件構成了閉包。作用域鏈上的變數物件————即外層作用域下的變數。
閉包就是函式,對變數、函式的訪問,也一樣是從其執行上下文中的作用域鏈上查詢。
需要強調的是,作用域鏈的構成為當前執行上下文中的變數物件(即當前作用域下的變數及函式)和函式定義時所能訪問到的變數物件集合(即函式定義時的位置的作用域鏈)。
function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined,?,?,? var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,? var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined,?,?,?
第一條解析:
開始js程式碼的執行,瀏覽器建立一個全域性執行上下文。呼叫fun
函式,var a = fun(0)
,在開始執行函式內部的程式碼前,瀏覽器解析器會建立一個函式執行上下文。並建立相應的執行上下文屬性scope chain
,初始化函式的形參為undefined
,因此var a = fun(0)
,會列印undefined
,因為函式形參o
在函式執行上下文的建立時被初始化為undefined
。
a.fun(1);a.fun(2);a.fun(3);
,這三條語句各自建立了一個函式執行上下文。
簡單地進行分析:
var a = fun(0)
fun(0)_EC = {
vo:{n:1,o:undefined}
}
所以列印了undefined
a.fun(1)
a.fun(1)_EC = {
scope_chain:[{m:1}]
}
執行a.fun(1)
時,內部也呼叫了fun(m,n)
EC={
scope_chain:
}