我們前面已經認識了函式作用域,也瞭解了回調函式,但有時候會產生意想不到的事情,造成內存問題,其中一個是閉包
閉包通常出現在巢狀函式中,是內部函式使用了外部函式的變數時,產生閉包!
首先我們用簡單的範例
function fn() {
var a = 1;
function plus1() {
a++
console.log(a);
}
return plus1;
}
var f = fn();
f();
我們透過 Google Chrome 的開發人員工具查看執行過程
可以看到在執行到第 8 行的時候,產生了閉包,也就是紅框處!
由此可見~閉包是在我們內部函式使用到了外部函式的變數時產生出來。
你可能想說第 9 行函式還沒執行呀!?
那是因為,函式的提升,所以導致執行到函式變數的時候就產生閉包。
而這時有被內部函式使用的變數,就會存在閉包之中!
就是我們上面的範例
function fn() {
var a = 1;
function plus1() {
a++
console.log(a);
}
return plus1;
}
var f = fn();
f(); // 2
f(); // 3
你會發現!函式內的變數 a
還存在可以累加並沒有消失,而這個值就存在 f
函式的閉包中!
沒錯!回調函式也會產生閉包~如下面範例
function consoleDelay (msg, time) {
setTimeout( function() {
console.log(msg)
}, time)
}
consoleDelay("我也是閉包", 2000);
一樣有形成閉包的條件!內部函式引用了外部函式的變數!
一般函式執行完畢後,就會從內存釋放,而閉包則是把函式內的變數,繼續保留在內存中(延長了局部變數的生命週期)。
一般函式內的變數無法從外部操作,但閉包可以間接操控函式內部的變數值。
函式執行完後,函式內的局部變數不會釋放,如果這個局部變數還會使用,那就是優點,如果不會使用了,那就變成缺點,因為佔用內存的時間會變長。
function fn() {
var arr = new Array(10000);
function arrLength() {
console.log( "內存有 " + arr.length + " 長度的陣列" );
}
return arrLength;
}
var f = fn();
f(); // 內存有 10000 長度的陣列
容易造成內存溢出與洩漏
盡量避免濫用閉包
及時釋放
f = null; // 讓內部函式變成「垃圾物件」,瀏覽器會自動清除
我們已經逐步學習 JavaScript 的核心精隨了!也是面試很長考的觀念~