Closure(閉包)

Jason
3 min readOct 29, 2023

--

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]()的閉包

結論

必包會記兩個重點
記住執行時的變數值 與 執行當時的環境

閉包的目的在於多人協作的時候,避免全域變數過多而地影響,讓變數留在函是中部被外部環境干擾,也可以用此特點固定一個參數值來做使用

--

--