工作處于實習階段,趁著現(xiàn)在還有點空閑時間,又忍不住掏出床頭的《JavaScript高級程序設計》,重新溫習了一遍。
在串講作用域和作用域鏈之前,先梳理清楚幾個重要概念。
執(zhí)行環(huán)境
執(zhí)行環(huán)境定義了變量或函數(shù)有權訪問的其他數(shù)據(jù),決定了他們各自的行為。每個執(zhí)行環(huán)境都有與其相關的變量對象。在web瀏覽器中,全局的執(zhí)行環(huán)境是window,因此全局變量和函數(shù)都是作為window對象的屬性和方法創(chuàng)建的。
變量對象
環(huán)境中定義的變量和函數(shù)都保存在變量對象中,解析器在處理數(shù)據(jù)的時候會在后臺使用它。(注:在函數(shù)的執(zhí)行環(huán)境中,變量對象稱為活動對象)
環(huán)境棧
每個函數(shù)都有自己的執(zhí)行環(huán)境,當執(zhí)行流進入一個函數(shù)時,函數(shù)的執(zhí)行環(huán)境被壓入環(huán)境棧中,當函數(shù)執(zhí)行完畢,函數(shù)從執(zhí)行棧中彈出,將控制權返回給之前的執(zhí)行環(huán)境。
弄清楚了以上概念,看代碼示例。
var leader = "shuDianZhang";
function employeeHouse() {
var hostName = "liHua"; // 主人名
var furniture = "sofa"; // 家具
function getFurniture() {
return furniture;
}
getFurniture();
}
employeeHouse();
執(zhí)行該代碼,首先壓入棧底的是全局執(zhí)行環(huán)境window,全局執(zhí)行環(huán)境中的變量對象上有變量leader和函數(shù)employeeHouse()。當執(zhí)行employeeHouse(),執(zhí)行流進入函數(shù)內部的時候,employeeHouse()的執(zhí)行環(huán)境壓入環(huán)境棧。代碼繼續(xù)執(zhí)行,當執(zhí)行getFurniture()函數(shù)的時候,其執(zhí)行環(huán)境繼續(xù)壓入環(huán)境棧。整個流程大致如下圖所示。
當getFurniture()函數(shù)執(zhí)行結束之后,getFurniture()函數(shù)的執(zhí)行環(huán)境從環(huán)境棧中彈出,緊接著,employeeHouse()函數(shù)的執(zhí)行環(huán)境從環(huán)境棧中彈出,當我們關閉網(wǎng)頁或者瀏覽器時,全局執(zhí)行環(huán)境自動銷毀。
作用域
在JavaScript中是沒有塊級作用域的。作用域只有全局作用域和局部作用域(函數(shù)的執(zhí)行環(huán)境)之分。也許是為了彌補JavaScript這一設計缺陷,在ES6中引入了let。
作用域鏈
在了解作用域鏈之前,我們不妨設想作用域鏈的用途是什么?如果沒有作用域鏈,結果會是怎樣?如果沒有作用鏈,就相當于缺少了一套訪問變量和函數(shù)的規(guī)則,沒有了這套規(guī)則的約束,就不能明確變量和函數(shù)的作用范圍,說白了就會亂套。因此,作用域鏈的用途,是保證對執(zhí)行環(huán)境有權訪問的所有變量和函數(shù)的有序訪問。作用域鏈的制定的規(guī)則就是內部環(huán)境可以通過作用域鏈訪問所有外部環(huán)境,但是外部環(huán)境不能訪問內部環(huán)境中的任何變量和函數(shù)。作用域鏈的搜所過程是:從作用域鏈的前端開始,向上逐級查詢與給定名字匹配的標識符。如果找到了,搜索過程停止,否則繼續(xù)沿著作用域鏈向上搜索,一直追溯到全局執(zhí)行環(huán)境中的變量對象為止。
當代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈。作用域鏈的前端始終是當前執(zhí)行的代碼所在環(huán)境的變量對象。作用域鏈的末端始終是全局執(zhí)行環(huán)境的變量對象。
好了好了,重點來了。為了方便記憶,我們把作用域鏈看作是一串燒烤。(夜晚寫這個,肚子有點餓了)假定這串燒烤是羊肉串,那么穿在這竹簽上的羊肉便是變量對象。
以最開始的代碼段為例,當代碼執(zhí)行getFurniture()函數(shù),執(zhí)行流進入getFurniture()函數(shù)內部的時候,可以知道,當前執(zhí)行的代碼所在環(huán)境是getFurniture()的執(zhí)行環(huán)境。這時候,可以想象服務員遞給你一串“羊肉串”,羊肉串的最頂端就是getFurniture()執(zhí)行環(huán)境的變量對象。
好了,作用域和作用域鏈的介紹先告一段落,后續(xù)會有補充,喜歡的朋友點個贊吧~一起學習,一起進步!