ItIron2021
Javascript
昨天我們簡單的帶過IIFE,今天的主題則比較刁鑽一些,會用到我們之前談過的許多觀念,也是很多面試者心目中的大魔王,但實際上並沒有這麼複雜! 我們馬上開始吧!
請解釋什麼是閉包(closure)
防雷圖來囉~!
沒錯,終究是逃不過這一關的! 我們昨天有稍微帶到這個關鍵字,這個觀念關係到js底層是如何運作的,但理解後其實也不是真這麼困難,若要用一句話來說的話,我會給出以下的解釋。
也就是不僅是函數本身,函數本身參照外部參數的行為就會製造出閉包,看個常見的例子
function demo() {
let name = 'Danny'
return function() {
console.log(`Hello, my name is ${name}`)
}
}
const demoFunc = demo()
demoFunc() // Hello, my name is Danny
上述就是閉包的典型範例,很多人會說閉包就是function return function,但實際上只要你的函數有參照到外部的參數就會形成閉包,例如這樣的做法也會產生一個閉包
let b = 5
function add(a) {
return a + b
}
閉包與一般函數的差別在於,一般函數中的變數在執行後就會從stack memory中消失,但由於閉包會需要不斷的參照外在環境的參數(以上方的例子來說就是b),他需要把那個參照的變數存在更長久保存的heap memory中不斷地引用,直到未來被js本身的垃圾回收機制處理掉。
既然閉包使用這麼麻煩,我們會什麼會需要閉包呢?
很好的問題,就像昨天提過的,遇到這樣的定義問題時,知道它是什麼遠遠不夠,最好是能給出一些為什麼需要它的理由或是一些實際的範例。js其實在很多你平常的使用中就有不斷用到閉包的概念,只是你沒有注意到而已,其中最主要的優勢為
藉由閉包你可以將一些函數或是變數私有化,讓它變得無法被外在的環境影響,藉由在閉包內創造一個私有的state,你可以確保這個變數、函數不會被預期之外的程式碼操作。
當然實際上閉包還有一些眉眉角角,有興趣的朋友別忘了作進一步的搜尋! 很多面試題目也經常會用到閉包的概念,例如一個萬惡的setTimeOut題目
for (var i = 1; i <= 5; i++) {
setTimeout(()=> {
console.log(i)
}, 100)
}
最終的輸出結果是5個6,你也許知道把var改為let就可以輕鬆印出目標的1~5,但...實際上這就是善用閉包的特性才能達到的,同時參照外部環境的行為是基於scope的特性,這你知道嗎??
閉包(closure)、scope
本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!
想請問一下~ setTimeOut題目,它的運算過程? 因為不是很懂閉包?
var i; // 只知道 var i 應該是被提升到外面??
for (var i = 1; i <= 5; i++) {
// 迴圈內不太了解 i 值的變化為甚麼直接跳到 i = 6 ??
setTimeout(()=> {
console.log(i)
}, 100)
}
@gior_ann 這個範例中i為什麼會變為6與閉包並沒有太直接的相關,會變為6主要是因為js有個處理同步與非同步程式碼的流程造成了這樣的結果。簡單來說當console.log(i)要執行時,其實整個迴圈早就跑完了,跑完迴圈後的i就是6(i === 5的時候還是會進入迴圈,跑完後+1變成6)
至於為什麼迴圈會早就跑完呢? 你可以參考昨天的Day20文章提供的內容與影片,如果看完還是很困惑歡迎你再繼續詢問囉!
哈哈 ~ 謝謝詳解
我再去看看day20 理解一下~