當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。作用域鏈的用途是保證對(duì)執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問。 ——《Javascript高級(jí)程序設(shè)計(jì)》
作用域(scope)指的是變量存在的范圍。在 ES5 的規(guī)范中,Javascript 只有兩種作用域:一種是全局作用域,變量在整個(gè)程序中一直存在,所有地方都可以讀??;另一種是函數(shù)作用域,變量只在函數(shù)內(nèi)部存在。要了解作用域,需要先了解執(zhí)行環(huán)境的相關(guān)概念。
執(zhí)行環(huán)境
執(zhí)行環(huán)境( execution context,簡(jiǎn)稱“環(huán)境” )是JavaScript中的重要概念之一。執(zhí)行環(huán)境定義了變量或函數(shù)有權(quán)訪問的其他數(shù)據(jù),決定了他們各自的行為。每個(gè)執(zhí)行環(huán)境都有一個(gè)與之關(guān)聯(lián)的變量對(duì)象,環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)對(duì)象中。
全局執(zhí)行環(huán)境是最外圍的一個(gè)執(zhí)行環(huán)境。在Web瀏覽器中,全局執(zhí)行環(huán)境被認(rèn)為是window對(duì)象,因此所有全局變量和函數(shù)都是作為window對(duì)象的屬性和方法創(chuàng)建的。某個(gè)執(zhí)行環(huán)境中的所有代碼執(zhí)行完畢后,該環(huán)境被銷毀,保存在其中的所有變量和函數(shù)定義也隨之銷毀(全局執(zhí)行環(huán)境知道應(yīng)用程序退出–例如關(guān)閉網(wǎng)頁或?yàn)g覽器—時(shí)才會(huì)被銷毀)
每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境。當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)時(shí),函數(shù)的環(huán)境就會(huì)被推入一個(gè)環(huán)境棧中。而在函數(shù)執(zhí)行后,棧將其環(huán)境彈出,把控制權(quán)返回給之前的執(zhí)行環(huán)境。
執(zhí)行環(huán)境的建立分為兩個(gè)階段:進(jìn)入執(zhí)行上下文(創(chuàng)建階段)和執(zhí)行階段(激活/執(zhí)行階段)
- 進(jìn)入上下文階段:發(fā)生在函數(shù)調(diào)用時(shí),但在執(zhí)行具體代碼之前。具體完成創(chuàng)建作用域鏈;創(chuàng)建變量、函數(shù)和參數(shù)以及求this的值
-
執(zhí)行代碼階段:主要完成變量賦值、函數(shù)引用和解釋/執(zhí)行其他代碼
總的來說可以將執(zhí)行上下文看作是一個(gè)對(duì)象
變量對(duì)象
每一個(gè)執(zhí)行環(huán)境都對(duì)應(yīng)一個(gè)變量對(duì)象(variable object),在該執(zhí)行環(huán)境中定義的所有變量和函數(shù)都存放在其對(duì)應(yīng)的變量對(duì)象中。
(1)進(jìn)入執(zhí)行上下文時(shí),變量對(duì)象的初始化過程如下:
函數(shù)的形參:變量對(duì)象的一個(gè)屬性,其屬性名就是形參的名字,其值就是實(shí)參的值;對(duì)于沒有傳遞的參數(shù),其值為undefined;
函數(shù)聲明:變量對(duì)象的一個(gè)屬性,其屬性名和屬性值都是函數(shù)對(duì)象創(chuàng)建出來的,如果變量對(duì)象已經(jīng)辦好了相同名字的屬性,則替換它的值
變量聲明:變量對(duì)象的一個(gè)屬性,其屬性名即為變量名,其值為undefined;如果變量名和已經(jīng)聲明的函數(shù)名或者函數(shù)的參數(shù)名,則不會(huì)影響已經(jīng)存在的屬性
(2)執(zhí)行代碼階段,變量對(duì)象中的一些屬性u(píng)ndefined值將會(huì)確定
活動(dòng)對(duì)象
當(dāng)函數(shù)被調(diào)用的時(shí)候,一個(gè)特殊的對(duì)象–活動(dòng)對(duì)象將會(huì)被創(chuàng)建。這個(gè)對(duì)象中包含形參和arguments對(duì)象?;顒?dòng)對(duì)象之后會(huì)作為函數(shù)上下文的變量對(duì)象來使用。換句話說,活動(dòng)對(duì)象除了變量和函數(shù)聲明之外,它還存儲(chǔ)了形參和arguments對(duì)象。
作用域鏈
已知,當(dāng)函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)變量對(duì)象的作用域鏈。而首先加入的變量對(duì)象是當(dāng)前函數(shù)的活動(dòng)對(duì)象,即形參和arguments。下一個(gè)變量對(duì)象來自包含環(huán)境,即該函數(shù)所屬環(huán)境,在下一個(gè)變量對(duì)象來自下一個(gè)包含環(huán)境。這樣一直延伸到全局執(zhí)行環(huán)境,全局執(zhí)行環(huán)境的變量對(duì)象始終都是作用域鏈中的最后一個(gè)對(duì)象。