不斷更新:整理常見的閉包問題

不斷積累和整理在JavaScript中常見的閉包問題,不斷加深理解和學習運用:javascript


 參考MDN網址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closuresjava

閉包的官方定義: 閉包是由函數以及建立該函數的詞法環境組合而成。這個環境包含了這個閉包建立時所能訪問的全部局部變量(摘自MDN)瀏覽器

閉包的簡單理解:但願在另外一個做用域(好比在global中)訪問局部做用域中的某個變量或函數閉包

(在谷歌瀏覽器中調試,發生閉包會有closure字樣提示)異步

問題一:閉包的「雛形」:在全局做用域中訪問某局部做用域中的變量或函數:函數

function fn() {

  var name =  'zs';

  return function () {

    return name;  

  }

}

var f = fn();

var n = f(); 

//或者這樣寫: var n= fn()();

console.log(n) //zs

問題二:用閉包解決在for循環中綁定事件的問題性能

假設不使用閉包解決這個問題,點擊綁定的li的值輸出的都是最後的一個值,由於觸發點擊事件的時候for循環已經結束了,且在for循環的做用域中 i 的值不斷被覆蓋學習

var list = document.getElementByTagName('li');

for (var i = 0 ;i < list.length ;i++){
    var li = list[i];
    ( function (index){
         li.onclick = function(){
             alert( index );
        }    
    })(i)
}    

自執行函數從全局做用域中訪問for循環裏面的 i, 給每一個 i 都新開創了一個做用域,讓它保存i的值 spa

但過多的開創獨立做用域,會形成額外的開銷消耗性能,因此閉包有利有弊,像上面這種問題可使用let來解決調試

延伸:其餘解決改問題的方法(使用let定義i)

var list = document.getElementByTagName('li');

for (let i = 0 ;i < list.length ;i++){
         li.onclick = function(){
             alert( i );
        }    
}    

問題三:用閉包解決在for循環中 setTimeout() 的問題

 

console.log(111)
for ( var i = 0 ; i<3 ; i++){
     setTimeout(function () {
          console.log(i)
    }, 0 )  
}
console.log(222)

最後的執行結果:
111
222
3
3
3

 

當js執行到setTimeout時會將其自動放入異步隊列中去等待,直到主代碼執行完後再去執行異步隊列中的代碼,因而3個3會在最後出現

使用閉包的方法避免這種狀況:

console.log(111)
for ( var i = 0 ; i<3 ; i++){
    (function (index){
        setTimeout(function () {
          console.log(i)
        }, 0 )  
    })(i)
}
console.log(222)
輸出結果:
111
222
0
1
2

問題四:從閉包的角度給button等元素綁定事件demo

<a href="#" id="size-12">12</a>
<a href="#" id="size-14">14</a>
<a href="#" id="size-16">16</a>
function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;

size12size14 和 size16 三個函數將分別把 body 文本調整爲 12,14,16 像素。咱們能夠將它們分別添加到按鈕的點擊事件上。

總結:

 上面是閉包的幾個典型例子,除此以外閉包常見的問題還有用閉包模擬私有方法等等,同時要注意開創閉包後要給它賦值爲null來清除,避免其常駐內存,形成內存泄漏等問題影響性能,固然還有其餘方式。

閉包考量性能,既實用,同時也有弊端。

運用好閉包是掌握JS的重點之一。革命還沒有成功,同志仍需努力!

相關文章
相關標籤/搜索