在系列(四)中,我留下了自己的疑惑,其實我是有答案的。答案就是遵循"忽略原則"。如果不忽略整個執行機制想必會亂套。MMP
繼續我的變數物件筆記記錄...
為了更加深刻地理解變數物件,這回我們結合一些例項來探討。
5.1 例項分析
//demo01
function test() {
console.log(a);
console.log(foo());
var a = 1;
function foo() {
return 2;
};
}
test();複製程式碼
當執行test函式時,我們說他對應的執行上下文被啟用(建立)。我們知道執行上下文的生命週期有兩個階段(建立階段和執行階段)。在這裡我們用如下形式來表達這個過程:
//建立過程
testEC = {
VO: {}, //變數物件
scopeChain: [], //作用域鏈
this: {}
}
//學習js是漸進增強的過程,所以這裡對作用域鏈和this不做過多解釋,目前我們只關注變數物件(VO)
VO = {
arguments: {...},
foo: <foo reference> //函式應用
a: undefined
}複製程式碼
在call stack中,如果當前執行上下文處於call stack的棧頂,則意味著這個執行上下文出於啟用狀態,此時變數物件稱之為活動物件(AO, Activation Object)。活動物件包含變數物件的所有屬性,並且此時所有的屬性都已完成賦值(在這裡就需要注意了:變數賦值是發生在執行上下文的執行階段),除此之外,活動物件還包含了this指向。
//執行階段
VO -> AO
AO = {
arguments: {},
foo: <foo reference>,
a: 1,
this: window
}複製程式碼
因此上面例子實際執行順序為:
function test() {
function foo() {
return 2;
}
var a = undefined;
console.log(a);
console.log(foo());
a = 1;
}
test();複製程式碼
下面我們再來看個例子鞏固一下:
//demo02.js
function test() {
consloe.log(foo);
console.log(bar);
var foo = 'Hello';
console.log(foo);
var bar = function() {
return 'world';
}
function foo() {
return 'hello'
}
}
test();複製程式碼
執行test函式時,對應的上下文開始建立,可以用如下形式來表達這個過程:
//建立過程
testEC = {
VO: {
arguments: {},
foo: <foo reference>,
bar: undefined
}, //變數物件
scopeChain: [], //作用域鏈
this: {}
}
//執行階段
VO -> AO
AO = {
arguments: {...},
foo: 'Hello',
bar: <bar referencer>,
this: window
}複製程式碼
融合整個知識點,相信您變數物件已經掌握了。
5.2 全域性上下文的變數物件
以瀏覽器為例,全域性物件為window物件。
全域性上下文的變數物件有一個特殊的地方,即他的變數物件就是window物件,而且全域性上下文的變數物件不能變成活動物件。
除此之外,全域性上下文的生命週期與程式的生命週期一致,只要程式執行不結束(比如關掉瀏覽器視窗),全域性上下文就會一直存在,其它所有的執行上下文都能直接訪問全域性上下文的屬性(這一點很重要)。
到這裡,我的變數物件學習過程也就結束了。
記住:執行上下的生命週期、變數物件->活動物件、全域性上下文的特殊性。
這些都是我以往的學習筆記。如果您看到此筆記,希望您能指出我的錯誤。有這麼一個群,裡面的小夥伴互相監督,堅持每天輸出自己的學習心得,不輸出就出局。希望您能加入,我們一起終身學習。歡迎新增我的個人微訊號:Pan1005919589