本次筆記主要記錄了:
閉包與垃圾回收機制的關係,
閉包與作用域鏈的關係。
8.1 閉包與垃圾回收機制
在系列(二)中,我提到了垃圾回收機制,知道當一個值失去引用之後就會被標記,然後被垃圾回收機制回收並釋放空間。
我們知道,當一個函式的執行上下文執行完畢之後,內部所有內容都會失去引用而被垃圾回收機制回收。
我們還知道,閉包的本質就是在函式外部保持了內部變數的引用,因此很明顯閉包會阻止垃圾回收機制回收。
下面我們就用一個例子來證明這一點。
function f1() {
var n = 999;
nAdd = function() {
n += 1;
}
return function f2() {
consloe.log(n);
}
}
var result = f1();
result(); //999
nAdd();
result(); //1000複製程式碼
從上面的例子可以看出,因為nAdd、f2都訪問了f1中的n,因此它們都與f1形成了閉包。這個時候變數n的引用被保留了下來。因為f2與nAdd執行時都訪問了n,而nAdd每執行一次就會將n加1.
認識到閉包中儲存的內容不會被釋放之後,我們就應該謹慎使用閉包。因為誰都知道,閉包的濫用可能會導致記憶體洩露因而影響程式效能。
8.2 閉包與作用域鏈
在開始之前,先思考一個問題,閉包會導致函式的作用域鏈發生改變嗎?
我們結合下面的例子來分析一下。
var fn = null;
function foo() {
var a = 2;
function innerFoo() {
console.log(a);
}
fn = innerFoo; // 將innerFoo的引用賦值給全域性變數中的fn
}
function bar() {
fn(); //此處保留innerFoo的引用
}
foo();
bar(); //2複製程式碼
在這個例子中,foo內部的innerFoo訪問了foo的變數a。因此當innerFoo執行時會有閉包產生,這是一個比較簡單的閉包的例子。不一樣的地方在與全域性變數fn。fn在foo內部獲取了innerFoo的引用,並在bar中執行。
那麼innerFoo的作用域鏈會是怎麼樣的呢?
在這裡需要特別注意的地方是函式呼叫棧與作用域鏈的區別:
因為call stack其實是在程式碼執行時才確定的,而作用域的規則在程式碼編譯階段就已經確定了。雖然作用域鏈的在程式碼執行時才生成的,但是他的規則不會隨著程式碼執行而發生變化。
so,這裡的閉包的存在並不會導致作用域鏈發生變化。
這些都是我以往的學習筆記。如果您看到此筆記,希望您能指出我的錯誤。有這麼一個群,裡面的小夥伴互相監督,堅持每天輸出自己的學習心得,不輸出就出局。希望您能加入,我們一起終身學習。歡迎新增我的個人微訊號:Pan1005919589