完全是些零碎的總結(jié)↓
變量提升?
栗子:
function test(){
console.log(foo);
var foo=1;
}
對(duì)于可執(zhí)行代碼,在其執(zhí)行之初會(huì)有一個(gè)分析的過(guò)程,分析時(shí)會(huì)預(yù)處理函數(shù)的活動(dòng)對(duì)象(AO),此時(shí)AO內(nèi)部的foo初值為undefined,只有當(dāng)真正執(zhí)行到var foo時(shí),才會(huì)賦值1,由于console.log在var之前,所以打印的foo是undefined(此時(shí)AO.foo=undefined)
簡(jiǎn)而言之:變量能提升是因?yàn)榉治鲞^(guò)程中,var聲明的鍵被初始化了。
思維導(dǎo)圖?
- 可執(zhí)行代碼
- 全局代碼
- 函數(shù)
- eval
- 執(zhí)行上下文棧
-
變量對(duì)象(Variable object,VO):執(zhí)行上下文相關(guān)的數(shù)據(jù)作用域,存儲(chǔ)上下文定義的變量、聲明
https://github.com/mqyqingfeng/Blog/issues/5 ←看這個(gè) -
作用域鏈(Scope chain)
https://github.com/mqyqingfeng/Blog/issues/6 ←看這個(gè) - this
-
變量對(duì)象(Variable object,VO):執(zhí)行上下文相關(guān)的數(shù)據(jù)作用域,存儲(chǔ)上下文定義的變量、聲明
閉包?
JS是詞法(靜態(tài))作用域,其作用域在創(chuàng)建(而不是執(zhí)行時(shí))確定,所以
let value = 1;
function foo() {
console.log(value);
}
function bar() {
let value = 2;
foo();
}
bar();
結(jié)果是value=1
原因是
1.foo和bar被在全局代碼中被創(chuàng)建,此時(shí)會(huì)初始化AO,作用域鏈,this,
2.foo和bar的作用域鏈都是[自己的AO,global.AO]
3.所以打印結(jié)果是1
這里涉及的作用域鏈,其完全與函數(shù)內(nèi)部一個(gè)叫做[[Scopes]]的屬性有關(guān),不信看下例閉包
function foo() {
let a=1
function bar() {
console.log(a)
}
return bar
}
console.dir(foo());
//打印結(jié)果↓↓
f bar()
arguments: null
caller: null
length: 0
name: "bar"
prototype: {constructor: ?}
__proto__: ? ()
[[FunctionLocation]]: VM50:3
[[Scopes]]: Scopes[2]
0: Closure (foo) {a: 1}
1: Global {window: Window, self: Window, document: document, name: "", location: Location, …}
[[Scopes]]內(nèi)包含的就是變量對(duì)象VO,函數(shù)執(zhí)行時(shí)找變量就是從Scopes的VO按序遍歷來(lái)尋找的。
根據(jù)上面的解析過(guò)程,我們也可以如法炮制
原因:
1.全局代碼下foo被創(chuàng)建,初始化AO,作用域鏈,this,此時(shí)foo的作用域鏈?zhǔn)荹foo.AO,global.AO]
2.執(zhí)行foo
3.bar被創(chuàng)建,此時(shí)bar的作用域鏈?zhǔn)荹bar.AO,foo.[[Scopes]]]==[bar.AO,foo.AO,global.AO]
4.返回bar
5.bar的scopes沒有變化,當(dāng)然被保存了呀,所以閉包