Joez87
Sep 21, 2021

--

Javascript學習筆記-有趣的closure

如果有在找尋javascript職缺,應該很容易被問到closure。如果不懂JS的closure,那麼以下有很多操作都會看不懂。

那麼closure是甚麼呢?以定義來說稱為"涵式及該涵式被宣告時所在的作用域環境之組合。

以下將透過幾個例子來了解javascript的closure。

function foo(){
var a="hey";
return function hey(){
console.log(a)
}
}

由於hey裡沒有a這個變數,則向外查找到a,以scope來說hey()是在foo()的裡面,所以能夠使用foo()的a。要是foo裡也沒有a,就會再向外尋找直到頂層。以上都還蠻直觀的。

這樣的迴圈你覺得console.log印出的會是甚麼呢?

for(var i=0;i<3;i++){
setTimeout(()=>{
console.log(i);
},1000);
}

.

.

.

你以為是0,1,2嗎,如果是0,1,2我就不會這樣問了。按下f12將它複製貼上,然後你就會看到1秒過後出現了三次的3,WTF 怎麼會這樣呢?

首先來解析一下,var 變數的作用域不在區塊而是function,根據其hoisting特性,也可以寫成這個樣子:

var i=0;
for(;i<3;i++){
setTimeout(()=>{
console.log(i)
},1000)
}

由於setTimeout的特性,console.log(i)會被放在event queue,此時console.log參考的i值,則是等for迴圈跑完i變成3之後才印出。

如果想印出0,1,2,有兩種解法,一種是將var改成let,另外一個則是使用立即涵式。

let 與var 的作用域不同,let 為區塊,var則是在function,所以以上述例子來說console.log參照的i值則是迴圈跑完的最終值3。那麼這個時候只要將var換成let則問題就解決了。

以立即涵式來說,它會在每次執行時將參考的值複製一份過去使用,即可解決這樣的問題。

for(var i=0;i<3;i++){
(function(j){
setTimeout(()=>{
console.log(j)
},1000)
}(i))
}

再看以下的例子:

function add(x){
return function addhelper(y){
return x+y
}
}
var add5=add(5);
var add10=add(10);
console.log(add5(2))//7
console.log(add10(2))//12

以這樣function內回傳另外一個function的方法就稱為涵式工廠(function factory)。

為何add5與add10的值會有所不同呢?不是都是add()嗎?

雖然他們使用同一個涵式,不過add5與add10為兩個不同的執行環境。

以上為closure的學習紀錄,如果有哪邊寫錯的再麻煩鞭小力一點,有問題也可以留言~

--

--

Joez87
0 Followers

輸出的才是真的學到的