所謂閉包

所謂閉包

Closures (閉包)是使用被作用域封閉的變量,函數,閉包等執行的一個函數的作用域。通常我們用和其相應的函數來指代這些作用域。(可以訪問獨立數據的函數)
閉包是指這樣的作用域,它包含有一個函數,這個函數可以調用被這個作用域所封閉的變量、函數或者閉包等內容。通常我們通過閉包所對應的函數來獲得對閉包的訪問。-----閉包-MDN

上面是MDN對閉包的定義,可以理解為:閉包是 JS 函數作用域的副產品。
換句話說,正是由于 JS 的函數內部可以使用函數外部的變量,所以正好符合了閉包的定義,而非JS 故意要使用閉包。

所以只要你懂了 JS 的作用域,你自然而然就懂了閉包,即使你不知道那就是閉包!

下面我們通過一個經典面試題來分析一下

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

上面代碼在頁面加載后就會執行,當i的值為4的時候,判斷條件不成立,for循環執行完畢,但是因為每個span的onclick方法這時候為內部函數,并沒有執行,這里的i是全局變量,i被引用,內存不能被銷毀,i的值會一直保持4,直到程序改變它或者所有的onclick函數銷毀(主動把函數賦為null或者頁面卸載)時才會被回收。

這樣每次我們點擊span的時候,onclick函數會查找i的值(作用域鏈是引用方式),一查等于4,然后就alert給我們了。而下面這種方式是使用了一個立即執行的函數又創建了一層閉包,這時候把i當參數傳入,函數立即執行,num保存每次i的值,這里的num是這個立即執行函數的私有變量。所以 這里每次點擊會彈出不同的值,

for (var i = 0; i < spans.length; i++) {
  !function(num) {
      spans[i].onclick = function() {
          alert(num);
      }
  }(i);
}

作用域

JS語言的特別之處就在于:函數內部可以直接讀取全局變量,但是在函數外部無法讀取函數內部的局部變量。
*注意點:在函數內部聲明變量的時候,一定要使用var命令。

關于作用域的詳細知識可以參見我的另外一篇文章----函數與作用域

閉包的作用

  1. 讓你在一個局部變量作用域之外也可以訪問到這個局部變量!!如下代碼就可以實現在fn外部訪問變量a,
  2. 另一個作用就是讓這些變量的值始終保持在內存中,不會在函數調用后被自動清除。比如下面的代碼中的fn調用執行后,變量a并沒有被瀏覽器的垃圾回收機制(garbage collection)回收。
function fn() {
  var a = xxx;
  return function (){
    return a;
  }
}

有人會說這就造成了內存泄露

錯!!!這個問題本身就有問題,內存泄露是指你用不到(訪問不到)的變量,依然占居著內存空間,不能被再次利用起來。

閉包里面的變量明明就是我們需要的變量,憑什么說是內存泄露?比如剛剛的代碼中的變量a!!!

這個謠言是如何來的?

因為 IE。IE 有 bug,IE 在我們使用完閉包之后,依然回收不了閉包里面引用的變量。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容