Closure(閉包) : 執行環境結束後仍可讓scope chain 引入該記憶體位置的功能
function greet(whatToSay){
return function(name){
console.log(whatToSay + ' ' + name)
}
}
const en = greet('Hello')
en('Astor') // Hello Astor
const sp = greet('Hola')
sp('Astor') // Hola Astor
如greet函數,在const en = greet('Hello')
執行完這個執行環境之後,將whatToSay
的記憶體空間留下來,即便greet執行環境已經不在了,仍可以在執行en('Astor')
scope chain 引入whatToSay
你想一下這下面會印出甚麼?
function buildFunction(){
const arr = []
for(var i = 0; i < 3; i++){
arr.push(
function(){
console.log(i)
}
)
}
return arr
}
const fs = buildFunction()
fs[0]()
fs[1]()
fs[2]()
是 0 1 2 嗎?
答案是 3 3 3
原因,是在執行arr.push()
的時候console.log(i)
只是被推進陣列裡
所以在執行fs[0]()
的時候scope chain找到的i
已經是3
有兩種寫法可以給你像要的 0 1 2
方法1
function buildFunction1() {
const arr = []
for (let i = 0; i < 3; i++) {
arr.push(
function () {
console.log(i)
}
)
}
return arr
}
const fs1 = buildFunction1()
fs1[0]()
fs1[1]()
fs1[2]()
ES6有let
變數,i
的範圍就會在{}
裡,每一次for
迴圈i
都會是記憶體裡面的新變數
方法2
function buildFunction2() {
const arr = []
for (var i = 0; i < 3; i++) {
arr.push(
(function (j) {
return function(){
console.log(j)
}
}(i))
)
}
return arr
}
const fs2 = buildFunction2()
console.log(fs2[0])
fs2[0]()
fs2[1]()
fs2[2]()
因為在執行arr.push()
的時候推進去arr裡用IIFE執行function(j)
return
function( ){console.log( j )}
後面的(i)
就是之後執行該fs2[0]()
的閉包
結論
『必包會記兩個重點
記住執行時的變數值 與 執行當時的環境』
閉包的目的在於多人協作的時候,避免全域變數過多而地影響,讓變數留在函是中部被外部環境干擾,也可以用此特點固定一個參數值來做使用