對於 JavaScript 程序員來講,閉包(closure)是一個難懂又必需要知道的東西。其實閉包很easy,只是太過理論術語,感受好像很複雜而已。下面就帶着輕鬆的心態,來戰勝閉包吧。node
簡單一句話,當一個函數裏面嵌套了一個函數的,而且內部函數用到了外部函數裏的變量時,這個總體就造成了一個閉包結構。但主要是這個結構有啥特色?有啥用?程序員
看一個例子:bash
var func = function(){
var a = 1;
return function(){
a++;
console.log ( a );
}
};
var f = func();
f(); // 輸出:2
f(); // 輸出:3
複製代碼
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:點擊對應節點,彈出對應的位置索引。索引
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了.
固然,也有不少種方法能夠實現這個需求,由於今天講的是閉包,就不說別的了。
閉包的造成條件
閉包的特色
若有錯誤,歡迎你們糾正