什么是閉包?
閉包的定義其實(shí)很簡(jiǎn)單:函數(shù) A 內(nèi)部有一個(gè)函數(shù) B,函數(shù) B 可以訪問(wèn)到函數(shù) A 中的變量,那么函數(shù) B 就是閉包。舉例:
const a = function() {
let n = 1
return function() {
console.log(n)
n++
}
}
const b = a()
b() // result: 1
b() // result: 2
在 JS 中,閉包存在的意義就是讓我們可以間接訪問(wèn)函數(shù)內(nèi)部的變量。
循環(huán)中使用閉包解決 var 定義函數(shù)的問(wèn)題
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i)
}, i*1000)
}
//result;全是 6
因?yàn)?setTimeout 是個(gè)異步函數(shù),所以會(huì)先把循環(huán)全部執(zhí)行完畢,這時(shí)候 i就是 6 了,所以會(huì)輸出一堆 6。
解決辦法(三種)
一、使用閉包
for (var i = 1; i <= 5; i++) {
;(function timer(j) {
setTimeout(function() {
console.log(j)
}, j*1000)
})(i)
}
// result: 1 2 3 4 5
在上面的代碼中,我們使用立即執(zhí)行函數(shù)將 i 傳入函數(shù)內(nèi)部,這個(gè)時(shí)候值就被固定在了參數(shù) j 上面不會(huì)改變,當(dāng)下次執(zhí)行 timer 這個(gè)閉包的時(shí)候,就可以使用外部函數(shù)的變量 j,從而達(dá)到目的。(其實(shí)相當(dāng)于創(chuàng)建了 5 個(gè)函數(shù)作用域, timer 執(zhí)行的時(shí)候就在自己的作用域里去訪問(wèn) j 的值,而不是統(tǒng)一訪問(wèn) i)
第二種就是使用 setTimeout 的第三個(gè)參數(shù),這個(gè)參數(shù)會(huì)被當(dāng)成 timer 函數(shù)的參數(shù)傳入。
for (var i = 1; i <= 5; i++) {
setTimeout(
function timer(j) {
console.log(j)
},
i * 1000,
i
)
}
第三種就是使用 let 定義 i 了來(lái)解決問(wèn)題了,這個(gè)也是 最為推薦 的方式
for (let i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i)
}, i * 1000)
}