在ECMASscript中的代碼有三種類型:global, function和eval(eval是通過傳入字符串動態(tài)的插入代碼,后面的代碼并不知道eval中代碼是什么)危号。每一種類型都有它們自己的執(zhí)行上下文。只有一個全局執(zhí)行上下文干奢,可能有多個function和eval的執(zhí)行上下文另患。一個函數(shù)可以生成無數(shù)個執(zhí)行上下文,甚至遞歸芳绩。執(zhí)行上下文掀亥,或者全局上下文調(diào)起全局的一個函數(shù)上下文,這叫執(zhí)行上下文棧妥色。調(diào)起其他上下文的上下文被稱為caller搪花。被調(diào)起的上下文被成為callee。當一個caller激活一個callee的時候嘹害,一個執(zhí)行上下文就會被callee激活鳍侣。callee某些時候也會是調(diào)用其他callee的caller
。當caller調(diào)起callee吼拥,caller暫停執(zhí)行,將控制流傳遞給callee线衫。callee被放進 執(zhí)行上下文棧凿可。
程序執(zhí)行最開始是在執(zhí)行上下文棧的最底部的全局執(zhí)行上下文。然后全局上下文提供了一些初始化,創(chuàng)造所需要的對象以及函數(shù)枯跑。全局上下文執(zhí)行期間惨驶,代碼會激活其他已經(jīng)創(chuàng)建的函數(shù),進入新的執(zhí)行上下文敛助,push新的元素到棧中粗卜。初始化執(zhí)行之后,運行系統(tǒng)會等待其他激活函數(shù)或者進入新的上下文的時間纳击。在下圖中续扔,有類似E1的執(zhí)行上下文和globalEC全局執(zhí)行上下文,通過globalEC改變進入或推出EC1.
這就是ECMAscript的運行系統(tǒng)如何管理代碼的執(zhí)行。
每個執(zhí)行上下文可以呈現(xiàn)為一個對象焕数,我們來看一下他的結構和什么狀態(tài)下執(zhí)行上下文執(zhí)行他的代碼纱昧。
- 執(zhí)行上下文
一個執(zhí)行上下文可以抽象的被表示成一個對象。每個執(zhí)行上下文設置的屬性(我們可以叫做執(zhí)行上下文的狀態(tài))堡赔,需要跟蹤執(zhí)行上下文進程的相關代碼识脆。下面的圖呈現(xiàn)的是執(zhí)行上下文的結構:
除了這三個需要的屬性(變量,this善已,作用域鏈)灼捂,一個執(zhí)行上下文的實現(xiàn)可能需要增加額外的狀態(tài)。
- 變量對象
變量對象是存放這執(zhí)行上下文相關數(shù)據(jù)的容器换团,他是存儲定義在上下文中變量和函數(shù)聲明的對象悉稠。
注意:變量中不包含函數(shù)表達式(對比函數(shù)聲明)。
變量是抽象概念啥寇,在不同的上下文類型中偎球,運用不同的對象。比如:在全局執(zhí)行上下文中辑甜,變量對象是全局對象本身(這就是為什么我們能夠通過全局對象的屬性名引用全局對象)衰絮。
- 激活對象
- 作用域鏈
- 閉包
- this
不同execution context的變項不會互相影響─了解function背後運作的邏輯
閉包:使用靜態(tài)作用域是閉包的一個強制性要求。
// global "x"
var x = 10;
// global function
function foo() {
console.log(x);
}
(function (funArg) {
// local "x"
var x = 20;
// there is no ambiguity,
// because we use global "x",
// which was statically saved in
// [[Scope]] of the "foo" function,
// but not the "x" of the caller's scope,
// which activates the "funArg"
funArg(); // 10, but not 20
})(foo); // pass "down" foo as a "funarg"
還有一個很重要的點磷醋,幾個函數(shù)可能含有相同的父級作用域(這是一個很普遍的情況猫牡,例如有好幾個內(nèi)部或者全局的函數(shù))。在這種情況下邓线,在[[Scope]]中存在的變量是會共享的淌友。一個閉包中變量的變化,也會影響另一個閉包的骇陈。
function baz() {
var x = 1;
return {
foo: function foo() { return ++x; },
bar: function bar() { return --x; }
};
}
var closures = baz();
console.log(
closures.foo(), // 2
closures.bar() // 1
);
this:
this是和執(zhí)行的上下文環(huán)境息息相關的一個特殊對象震庭。因此,它也可以稱為上下文對象[context object]你雌。this是執(zhí)行上下文環(huán)境的一個屬性器联,而不是某個變量對象的屬性二汛。
在函數(shù)上下文[function context]中,this會可能會根據(jù)每次的函數(shù)調(diào)用而成為不同的值.this會由每一次caller提供,caller是通過調(diào)用表達式[call expression]產(chǎn)生的(也就是這個函數(shù)如何被激活調(diào)用的)拨拓。