淺析JavaScript作用域和作用域鏈

javascript.jpg

工作處于實習階段,趁著現(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)境棧。整個流程大致如下圖所示。


環(huán)境棧變化圖.png

當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)境的變量對象。

好了好了,重點來了。為了方便記憶,我們把作用域鏈看作是一串燒烤。(夜晚寫這個,肚子有點餓了)假定這串燒烤是羊肉串,那么穿在這竹簽上的羊肉便是變量對象

烤肉串類比圖.png

以最開始的代碼段為例,當代碼執(zhí)行getFurniture()函數(shù),執(zhí)行流進入getFurniture()函數(shù)內部的時候,可以知道,當前執(zhí)行的代碼所在環(huán)境是getFurniture()的執(zhí)行環(huán)境。這時候,可以想象服務員遞給你一串“羊肉串”,羊肉串的最頂端就是getFurniture()執(zhí)行環(huán)境的變量對象。

好了,作用域和作用域鏈的介紹先告一段落,后續(xù)會有補充,喜歡的朋友點個贊吧~一起學習,一起進步!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容