JS基礎:閉包和做用域鏈

簡介閉包

  一個定義在函數內部的函數與包含它的外部函數構成了閉包,內部函數能夠訪問外部函數的變量,這些變量將一直保存在內存中,直到沒法再引用這個內部函數。函數

例如:spa

var a = 0;
function outerFun(i) {
    var b = i;
    function innerFun(j) {
        var c = j;
        console.log("全局變量:"+a);
        console.log("外部變量:"+b);
        console.log("內部變量:"+c);
        a++;
        b++;
        c++;
    }
    return innerFun;
}
var testFun1 = outerFun(10);
testFun1(10);//全局變量:0 外部變量:10 內部變量:10
testFun1(10);//全局變量:1 外部變量:11 內部變量:10

var testFun2 = outerFun(20);
testFun2(20);//全局變量:2 外部變量:20 內部變量:20 
testFun2(20);//全局變量:3 外部變量:21 內部變量:20

結論:code

c 是 innerFun() 的局部變量,每次執行 innerFun() 都會從新賦值;
b 是 innerFun() 的上一級變量,每次執行 innerFun() 的結果會保存在內存中,是 outerFun() 的局部變量,每次執行 outerFun() 都會從新賦值;
a 是 innerFun() 的上上一級變量,每次執行 innerFun() 的結果會保存在內存中,是 outerFun() 的上一級變量,每次執行 outerFun() 的結果也會保存在內存中;blog

  在JavaScript中,做用域只有全局做用域和函數級做用域兩種,在下一級做用域中能夠訪問和修改上一級做用域的變量,在定義函數時,JS會自動維護一個做用域鏈,當前的局部做用域位於做用域鏈頂端,並能夠依次向上回溯。閉包的實質就是延長了做用域鏈。ip

變量的生存週期內存

  上面提到,js 中只有全局變量和函數級的局部變量兩種,全局變量的生存週期固然是永久的,除非咱們主動銷燬這個全局變量。而對於在函數內用 var 關鍵字聲明的局部變量來講,當退出函數時,這些局部變量即失去了它們的價值,它們都會隨着函數調用的結束而被銷燬。作用域

例如:it

//頁面有5個 div,指望點擊每一個 div 輸出它的序號
for(var i=0; i<5; i++) {
    $('div').eq(i).on('click',function() {
        console.log(i);
    })
}

然而,實際上,點擊每一個 div 輸出的都是5,這是由於 i 是全局變量,位於做用域鏈最頂端,當改變 i 的值的時候,全部引用了它的函數都會受到影響,當循環運行結束後,i 的最終值爲5,因此點擊每一個 div 輸出的固然是5了。這時咱們能夠經過閉包來延長做用域鏈,爲 i 的值保存一個副本,使它們之間不會互相影響。io

例如:

for(var i=0; i<5; i++) {
    function outerFun() {
        var j = i;
        function innerFun() {
            $('div').eq(j).on('click',function() {
                console.log(j);
            })
        }
        innerFun();
    }
    outerFun();
}

這裏的 outerFun() 和 innerFun() 均可以用匿名自執行函數代替,例如:

for(var i=0; i<5; i++) {
    (function() {
        var j = i;
        (function() {
            $('div').eq(j).on('click',function() {
                console.log(j);
            })
        })();
    })();
}
相關文章
相關標籤/搜索