JS中的 閉包(Closure)

YXi發表於2019-09-02

什麼是閉包?

閉包就是能夠讀取其他函式內部變數的函式。

例如在javascript中,只有函式內部的子函式才能讀取區域性變數,所以閉包可以理解成“定義在一個函式內部的函式“。
在本質上,閉包是將函式內部和函式外部連線起來的橋樑。

程式碼演示:

function裡巢狀function時,內部的function可以訪問外部function裡的變數

function fn(x) {
  var tmp = 3;
  function bar(y) {
    alert(x + y + (++tmp));
  }
  bar(2);
}
fn(1)
複製程式碼

不管執行多少次,都會alert 7,因為bar能訪問fn的引數x,也能訪問fn的變數tmp

但是,這並 不是 不是 不是 閉包

當你return的是內部function時,才是閉包

內部functionclose-over外部function的變數直到內部function結束。

function fn(x) {
  var tmp = 3;
  return function (y) {
    alert(x + y + (++tmp));
  }
}
var bar = fn(1); // bar 現在是一個閉包
bar(2);
複製程式碼

上面的指令碼最終也會輸出alert 7,因為雖然bar不直接處於fn的內部作用域,但bar還是能訪問xtmp

但是,由於tmp仍存在與bar閉包的內部,所以它還是會自加1,而且你每次呼叫bar時它都會自加1。

其實,我們其實可以建立不止一個閉包方法,比如return它們的陣列,也可以把它們設定為全域性變數。它們全都指向相同的x和相同的tmp,而不是各自有一份副本。

一個需要關注的點:

JS裡處理object時是用到引用傳遞的,那麼,你呼叫fn時傳遞一個objectfn函式return的閉包也會引用最初那個object

function fn(x) {
  var tmp = 3;
  return function (y) {
    alert(x + y + tmp);
    x.memb = x.memb ? x.memb + 1 : 1;
    alert(x.memb);
  }
}
var tar = new Number(1);
var bar = fn(tar); // bar 現在是一個引用了tar的閉包
bar(2);
複製程式碼

不出我們意料,每次執行bar(2)x.memb都會自加1。但需要注意的是x每次都指向同一個object變數tar

這樣記憶體洩漏有關。

有一個不用return關鍵字的閉包例子:

function closureExample(obj, text, timedelay) { 
    setTimeout(function() { 
        document.getElementById(objID).innerHTML = text; 
        }, timedelay); 
} 
closureExample(‘myDiv’, ‘Closure is created’, 500); 
複製程式碼

總結:

JS裡的function能訪問它們的:

  • 引數
  • 區域性變數或函式
  • 外部變數

如果在一個函式中,又巢狀了一個函式,並且裡面這個函式引用外面的函式的變數,那麼就是閉包。

閉包的特點:

  • 閉包可以產生記憶體洩露
  • 閉包可以延長變數的生命週期

~_~

相關文章