輕鬆掌握js閉包

前言

對於 JavaScript 程序員來講,閉包(closure)是一個難懂又必需要知道的東西。其實閉包很easy,只是太過理論術語,感受好像很複雜而已。下面就帶着輕鬆的心態,來戰勝閉包吧。node

什麼是閉包?

簡單一句話,當一個函數裏面嵌套了一個函數的,而且內部函數用到了外部函數裏的變量時,這個總體就造成了一個閉包結構。但主要是這個結構有啥特色?有啥用?程序員

閉包的特色?

看一個例子:bash

var func = function(){ 
    var a = 1; 
     return function(){ 
        a++; 
        console.log ( a ); 
    }
};
var f = func(); 
f(); // 輸出:2 
f(); // 輸出:3 
複製代碼
解析:
  • 在上例中,func函數裏面返回了一個函數,也能夠說嵌套了一個子函數,內部函數裏用到了外部函數的變量a.此時造成了閉包結構。
  • 調用流程:首先f = func(),此時func()函數被調用,咱們都知道函數的局部變量會隨着函數調用的結束而被銷燬。可是f()調用以後發現依然能夠訪a變量,說明局部變量a並無被銷燬。這就是閉包的一個特性:父函數的局部變量若是在子函數中有用到,那麼這個局部變量就不會被銷燬。就是子函數在對父函數的呼喚,你別銷燬這個變量,我還要用呢。

OK,那麼瞭解了閉包的特性,就得知道有啥用吧,否則學了就沒啥意思了,接着往下看。閉包

閉包的做用?

建立私有做用域

使用場景1:實現一個業務,有多個函數。函數

粗暴的寫法:ui

var _count = 1;
    var m1 = function(){
        var b = _count + 1
    };
    
    var m2 = function(){
    };
複製代碼

這種寫法,就是什麼東西都暴露在全局下了,變量_count也會很容易被篡改。好的寫法,應該是,能讓外界訪問的就暴露給外界,不須要的外界就訪問不了。spa

此時咱們就能夠採用閉包:以下code

var module = (function(){
    var _count = 0;
    var m1 = function(){
    };
    
    var m2 = function(){
    };
    return {
        m1 : m1,
        m2 : m2
    };
})();

module.m1();

這樣 外界就訪問不到module的局部變量了,對應的操做暴露出來,又能夠訪問。
複製代碼

使用場景2:點擊對應節點,彈出對應的位置索引。索引

若是不經思考的話,你可能寫出以下的代碼,但實際上這樣寫,無論點哪一個都會彈出2
var nodes = document.getElementsByTagName( 'div' ); 
for ( var i = 0, i < 2; i++ ){ 
     nodes[ i ].onclick = function(){ 
        alert ( i ); 
     } 
}; 
複製代碼

解析: 首先,執行循環,每次循環都聲明一個點擊是事件,以下:事件

第一次循環
 nodes[0].onclick = function(){ 
    alert ( i ); 
} 
第二次循環
 nodes[1].onclick = function(){ 
    alert ( i ); 
} 

複製代碼

解析:首先,咱們要知道在js語言中,for循環不是一個代碼塊,也就是說沒有造成一個單獨的做用域,i在全局做用域均可以被訪問,因此,執行完循環後,i的值已經變成5.而事件只有在點擊的時候才執行內部的代碼,當咱們點擊的時候,此時彈出的i已是循環事後的i了,就是5了。

那怎麼樣才能實現咱們要的效果呢?既然想彈出對應的i,咱們在每次循環的時候,是否是就應該傳入一個惟一的i,也就是每一個i都有本身的做用域,不會被覆蓋。 想到做用域,那天然是想到函數了,因此咱們就在點擊事件外,包裹一個函數,把每次循環的i當作參數傳入進去, 此時參數是局部變量,以下:

var nodes = document.getElementsByTagName( 'div' ); 
for ( var i = 0, i < 2; i++ ){ 
    (function(j){
        nodes[ j ].onclick = function(){ 
            alert ( j ); 
        } 
    })(i)
     
}; 
複製代碼

解析: 其實此時,是否是造成了一個閉包結構了,當即執行函數內包裹了點擊事件函數,且點擊事件函數,用到了外層函數的變量j。因此這個j是不會被銷燬的,因此在點擊的時候,咱們天然就能訪問到對應函數的這個參數j了.

固然,也有不少種方法能夠實現這個需求,由於今天講的是閉包,就不說別的了。

總結

閉包的造成條件

  • 函數嵌套函數
  • 內部的函數引用了外部函數的參數和變量

閉包的特色

  • 外部函數中,被內部函數引用的參數和變量不會被銷燬

若有錯誤,歡迎你們糾正

相關文章
相關標籤/搜索