JavaScript 執(zhí)行環(huán)境與作用域、函數(shù)的創(chuàng)建和調(diào)用

來源 | http://www.fly63.com/article/detial/10179
執(zhí)行環(huán)境

執(zhí)行環(huán)境的銷毀
某個執(zhí)行環(huán)境在所有代碼執(zhí)行完畢后,這個執(zhí)行環(huán)境就會被銷毀,保存在其中的所有變量和函數(shù)定義也隨之銷毀。
全局執(zhí)行環(huán)境直到應(yīng)用退出,例如關(guān)閉網(wǎng)頁或瀏覽器時銷毀。
每個函數(shù)都有一個執(zhí)行環(huán)境,當(dāng)函數(shù)開始進(jìn)入執(zhí)行流時,會將此函數(shù)的執(zhí)行環(huán)境推入環(huán)境棧中,當(dāng)函數(shù)執(zhí)行完后,會將此函數(shù)的執(zhí)行環(huán)境從環(huán)境棧中彈出,將環(huán)境棧的控制權(quán)交還給之前的執(zhí)行環(huán)境。

作用域鏈
當(dāng)代碼在一個執(zhí)行環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈。
作用域鏈:保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問;作用域鏈的前端始終是當(dāng)前執(zhí)行代碼所在環(huán)境的變量對象。
如果執(zhí)行的是一個函數(shù),那么作用域鏈的前端就是函數(shù)的活動對象(activation object),在最初活動對象中只有一個變量arguments對象(該對象在全局環(huán)境中是不存在的),arguments對象是一個類數(shù)組對象,它包含著傳入該函數(shù)的所有參數(shù)。
作用域鏈中的下一個變量對象則來自于包含(外部)環(huán)境;
下一個變量對象則來自下一個包含環(huán)境;
.........
這樣一直延到全局執(zhí)行環(huán)境(見下圖)。(全局執(zhí)行環(huán)境始終是作用域鏈中的最后一個變量對象)
js中的標(biāo)識符解析就是沿著作用域鏈一級一級地搜索標(biāo)識符的過程。搜索過程始終做作用域鏈的前端開始(如下圖中的0級,如果是函數(shù)就是函數(shù)本身的活動對象),然后一級一級地向后回溯,直至找到標(biāo)識符為止。(如果找不到通常出錯)

《JavaScript高級程序設(shè)計中》例子來說明:
var color = "blue";function changeColor() {var anotherColor = "red";function swapColors(){var tempColor = anotherColor;anotherColor = color;color = tempColor;// 這里可以訪問tempColor、anothercolor、color}// 這里可以訪問anothercolor、colorswapColors();}// 這里只能訪問 colorchangeColor();
這段代碼中包括3個執(zhí)行環(huán)境,分別是全局執(zhí)行環(huán)境、changeColor()執(zhí)行環(huán)境、swapColor()執(zhí)行環(huán)境。
swapColors()可以訪問tmpeColor、anotherColor、color所有變量,changeColor()可以訪問anotherColor、color,changeColor只能訪問color。
從這個例子可以看出內(nèi)部環(huán)境可以通過作用域鏈訪問所有外部環(huán)境,但是外部環(huán)境不能訪問內(nèi)部環(huán)境中的任何變量和函數(shù)。這些環(huán)境之間是有線性的、有次序的。
每個環(huán)境都是向上搜索作用域鏈來查詢變量或者函數(shù)名,任何環(huán)境都不能向下搜索作用域鏈而進(jìn)入另一個執(zhí)行環(huán)境。
swapColors()作用域中包含3個對象:它自身的變量對象、changeColor()的變量對象和全局變量對象。swapColor()局部執(zhí)行環(huán)境開始時會先從自身的變量對象中搜索變量和函數(shù)名,如果搜索不到則搜索上一級作用域鏈。
函數(shù)執(zhí)行過程
function compare(value1,value2) {if(value1 < value2){return -1;}else if(value1 > vlue2){return 1;}else{return 0;}}var result = compare(2,5);
創(chuàng)建一個compare函數(shù),調(diào)用函數(shù)。下面解釋下函數(shù)創(chuàng)建和調(diào)用時候都做了哪些操作:
在創(chuàng)建compare()函數(shù)時,會創(chuàng)建一個預(yù)先包含了全局變量對象的作用域鏈存在函數(shù)內(nèi)部的[[scope]]屬性中;(說明:全局環(huán)境的變量對象始終存在。)
在調(diào)用compare()函數(shù)時,會為函數(shù)創(chuàng)建一個執(zhí)行環(huán)境,然后通過復(fù)制函數(shù)內(nèi)部的[[scope]]屬性中的對象構(gòu)建起執(zhí)行環(huán)境中的作用域鏈;
函數(shù)本身的活動變量被創(chuàng)建,在這里作為變量對象推入到作用域鏈的前端;
當(dāng)調(diào)用compare()的時候,創(chuàng)建了執(zhí)行環(huán)境,創(chuàng)建了作用域鏈,并創(chuàng)建了函數(shù)本身的活動對象,同時將此活動對象作為變量對象推入到了作用域的前端,在compare()函數(shù)的作用域鏈中,自身的活動對象處在作用域鏈的第一位,全局變量對象處于作用域的第二位。
在函數(shù)執(zhí)行過程中,讀取和寫入變量值時,都需要在作用域鏈中查找變量,無論什么時候查找變量,都是在作用域鏈中搜索相應(yīng)名字的變量。
作用域鏈本身是一個指向變量對象的指針列表,只包含引用不實際包含變量對象。

本文完?
學(xué)習(xí)更多技能
請點擊下方web前端開發(fā)
![]()

