js基礎知識(5)-閉包
阿新 • • 發佈:2018-11-22
閉包的定義很簡單:函式 A 返回了一個函式 B,並且函式 B 中使用了函式 A 的變數,函式 B 就被稱為閉包。
function A() {
let a = 1
function B() {
console.log(a)
}
return B
}
你是否會疑惑,為什麼函式 A 已經彈出呼叫棧了,為什麼函式 B 還能引用到函式A 中的變數。因為函式 A 中的變數這時候是儲存在堆上的。現在的 JS 引擎可以通過逃逸分析辨別出哪些變數需要儲存在堆上,哪些需要儲存在棧上
經典面試題,迴圈中使用閉包解決 var 定義函式的問題
for ( var i=1; i<=5; i++) { setTimeout( function timer() { console.log( i ); }, i*1000 ); }
首先因為 setTimeout 是個非同步函式,所有會先把迴圈全部執行完畢,這時候 i就是 6 了,所以會輸出一堆 6。
解決辦法一:使用閉包
for (var i = 1; i <= 5; i++) {
(function(j) {
setTimeout(function timer() {
console.log(j);
}, j * 1000);
})(i);
}
第二種就是使用 setTimeout 的第三個引數
for ( var i=1; i<=5; i++) { setTimeout( function timer(j) { console.log( j ); }, i*1000, i); }
第三種就是使用 let 定義 i 了
for ( let i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
因為對於 let 來說,他會建立一個塊級作用域,相當於
{ // 形成塊級作用域
let i = 0
{
let ii = i
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
i++
{
let ii = i
}
i++
{
let ii = i
}
...
}