再談JS閉包(JS閉包系列2)

這篇文章,來繼續(xù)談?wù)凧avascript閉包的剩余問題。因為在上一篇文章中關(guān)于JS閉包(JS閉包系列1)主要簡單的示例代碼直觀的觀察了下閉包,這篇文章就來從理論上好好地分析分析JS閉包的有關(guān)概念。

首先應(yīng)該知道的是JS中的作用域鏈(scope chain)概念:

(1)定義
每個人都有自己的生活環(huán)境,代碼也一樣,JS中的代碼都有自己的“執(zhí)行環(huán)境”。當(dāng)代碼在一個環(huán)境中定義時(函數(shù)調(diào)用之前),就會生成變量對象的作用域鏈。這個鏈條,從當(dāng)前環(huán)境中的變量對象開始,上溯至父環(huán)境(包含環(huán)境)中的變量對象,再到父環(huán)境的父環(huán)境中的變量對象···一直上溯到全局執(zhí)行環(huán)境的變量對象。想象著一條鎖鏈,從最下面開始爬,一直爬到最上頂端。每一個節(jié)點,代表著這一層級環(huán)境中的變量對象。

需要注意的是,作用域鏈?zhǔn)歉鶕?jù) 函數(shù)定義 時的位置確定的,而不是在調(diào)用時確定。這也叫做 詞法作用域

chain

(2)作用
作用域鏈用來保證那些有權(quán)訪問不同執(zhí)行環(huán)境的代碼,在對不同環(huán)境里的變量和函數(shù)訪問時的有序性以及確定性

(3)應(yīng)用
當(dāng)解析一個標(biāo)識符時,是沿著作用域鏈一級一級地上溯(回溯)搜索標(biāo)識符的過程。如果找不到標(biāo)識符,就會產(chǎn)生錯誤。

還是直接看代碼吧:

var color = "blue";  //全局作用域
function changeColor(){
    if(color === "blue"){ //尋找`color`,此作用域(函數(shù)內(nèi))沒有,則上溯到父級作用域,(這里是全局)找到了
          color = "red";
    }else{
          color = "blue";
    }
}
changeColor();
alert("Color is now " + color);

在這個例子中,函數(shù)changeColor的作用域鏈包含兩個對象:它自己的變量對象(每個函數(shù)都有的arguments對象),以及全局環(huán)境中的變量對象。

再來看一個多層作用域鏈?zhǔn)纠?/p>

var weibing = "在";  //最外層守衛(wèi)
var dajiangjun = "不在";  //2號大將軍
function chengqiang(){  //城墻內(nèi)
    var dajiangjun= "在";  //1號大將軍
    function gongdian(){  //宮殿內(nèi)
        var zaixiang = "不在";  //宰相
        if(zaixiang === "在")
             console.log("把宰相找來!");
        else if(dajiangjun === "在")
             console.log("把大將軍找來!");
        else
             console.log("把衛(wèi)兵找來!");
    }
     return gongdian();
}
 chengqiang();    

結(jié)果可想而知:


皇帝召見層級

想象這樣一個場景:皇帝身居寢宮,寂寞了,想要招納美女。那么首先想到的是宰相,他可以直接召見宰相,讓宰相給自己辦事。假如宰相不在,那么他可以召見大將軍(職級低于宰相),讓大將軍給自己干;碰巧,大將軍也去喝酒了,那就直接召見衛(wèi)兵。在這個例子中,皇帝找到大將軍了。但是有人會問,這段代碼里,有兩個dajiangjun?。Π?,可是,皇帝他老人家是從自己身邊找人的。最外邊的那個2號大將軍,雖然也在,但是他沒上朝,去考察去了。(沒在城墻內(nèi)),所以就召見1號大將軍嘍。而且自然而然,在城墻外邊的人(例如普通老百姓),當(dāng)然是見不到宰相和皇帝的啦。
例如在上面代碼下面加如下代碼:

function chixinwangxiang(){ //癡心妄想
      alert("把"+zaixiang+"給爺叫出來!");
}

結(jié)果是:


癡心妄想

在城墻外邊,你肯定是見不到一人之下,萬人之上的宰相大人啦!

(4)注意
因為在JS中,作用域里沒有以花括號包圍的“塊級作用域”概念,看一個例子:

if(true){
    var a = 1;
}
console.log(a);  //輸出1

表面上看來, a在if語句里面定義著,那么console語句應(yīng)該是訪問不了的,然而事實恰恰相反,因為在JS中,if或者for語句的花括號,根本不是獨立作用域,只有函數(shù)的花括號才起作用。

總結(jié):現(xiàn)在知道了作用域鏈的概念,而你應(yīng)該知道的是,閉包就是由作用域鏈引起的。下一節(jié),就要帶著作用域鏈的思維來思考閉包,那樣就簡單多了。因為你會發(fā)現(xiàn)那是順其自然。

本篇完

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容