Java陣營基於一種對語法的古怪堅持 (雖然我現在就覺得它的語法又臭又長) ,現在連 anonymous function 都不支持。要解說本例之前,還要先用 anonymous inner class 模擬 anonymous function 。接著再用模擬的 anonymous function 再去模擬 closure 。如此蹩腳的寫法如果還能像 JavaScript 一樣簡潔地表示本文要說明的內容,那也太不可思議了。
另外,我搜尋到 Martin Fowler 寫的 Closure 。他也寫了一個 JavaScript 的例子,我補到正文去了。
R@Ndy ,你提供的程式碼很有趣,但是不是省略了什麼?
例如說,是不是像下面這樣用?
var f = function(n){
return function(i){return n+=i;};
}
print( (f(2))(3) );
//In this case, n = 2, i = 3
Posted by 遊手好閒的石頭成
at 2007年05月24日 21:12
修正一下,方便說明:
var i = 0;
var fs = [];
function run_fs() {
for (var j = 0, f = fs[j]; f; f = fs[++j]) {
f();
}
}
for (i = 0; i < 3; ++i) {
fs[i] = function a(){print(i);}
}
run_fs();
for (i = 0; i < 3; ++i) {
fs[i] = (function b() {
var j = i * 3;
return function c(){print(j);}
})();
}
run_fs();
function e() {
var j = i * 2;
return function f(){print(j);}
}
for (i = 0; i < 3; ++i) {
fs[i] = e();
}
run_fs();
以 ECMAScript 3 Specification 的說法,
每一個客製 function 都有一個叫 [[Scope]] 的內部屬性紀錄了那個 function 在定義或宣告時的 scope chain ,每當呼叫 function 進入 function code 時,會產生一個叫 activation object 的新物件作為 function scope ,並把這個物件放在由 [[Scope]] 得到的 scope chain 的前頭,形成一個新的 scope chain ,function code 就是用這個新 scope chain 進行識別子解析(identifier resolution)。
根據數學定義, scope chain 就是 closure,而每次離開 function code ,可能被GC回收的是 activation object 這個 function scope,亦即是因為每次進入 function code 時,function scope 都是不同的,因而有不同 closure 。
函數 a 參照的 i 是在 a 的 [[Scope]] 中global object的變數 i ,因為雖然每次定義和呼叫的 a 是不同的 a ,但是是同一個 global object ,所以是參照到同一個 i 。
而函數 f 參照的 j 是 f 的 [[Scope]] 中屬於函數 e 的 activation object 的變數 j , 因為雖然每次呼叫的 e 是同一個 e ,但是是不同的 activation object ,所以是不同的 j 。