Closure is when a "function" "remembers" its lexical scope even when the function is executed outside that lexical scope. Closure 是指說一個function記住了他在被定義的當下時的lexical scope,即使function在執行的時候是在當時的lexical scope之外

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function foo() {
var bar = "bar";
function baz() {
console.log(bar); // reference bar
}
bam(baz); // 透過bam 傳出去
}
function bam(baz) {
baz(); // 在不同的環境下執行
}
foo();

function baz 裡面的bar 由於reference了 foo function中的bar

讓bar 變數可以在foo執行完後繼續存在在記憶體中

而不會被garbage collected

1
2
3
4
5
6
7
8
function foo(){
var bar = "bar";
setTimeout(function(){
console.log(bar)
},1000);
bar = "bar2"
}
foo() // "bar2"

因為bar reference的是變數

而不是變數的當下的值

所以當bar的值被改變成 "bar2" 後

console 出來的結果就會是 "bar2"

1
2
3
4
5
for (var i=1; i<=5; i++){
setTimeout(function(){
console.log("i: " + i);
}, i * 1000)
}

這段程式碼執行出來的結果會是

1
2
3
4
5
i: 6
i: 6
i: 6
i: 6
i: 6

原因是在於所有的i都是reference 了 global scope底下的i

當loop結束後 setTimeout的event被觸發時

所console.log出來的結果就會像上面顯示的那樣

這樣的情況要如何解決呢?

可以透過function去create出一個新的scope

1
2
3
4
5
6
7
for (var i=1; i<=5; i++){
(function(i){
setTimeout(function(){
console.log("i: " + i);
}, i * 1000)
})(i);
}

下面的code會console出"bar"

但他是closure嗎?

1
2
3
4
5
6
var foo = (function(){
var o = { bar: "bar" };
return {obj: o};
})();
console.log(foo.obj.bar); // "bar"

Closure 是指說一個function記住了他在被定義的當下時的lexical scope,即使function在執行的時候是在當時的lexical scope之外

上述的例子並不是透過function去reference,而只是單純的object reference

module pattern javascript

用Closure可以將javascript module化

將原有的function包在IIFE當中

透過return 內部的function 作為public API

讓外部程式可以執行module內部的程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var foo = (function() {
var publicAPI = {
bar: function(){
publicAPI.baz();
},
baz: function(){
console.log("baz");
}
}
return publicAPI;
})();
foo.baz()