前面稍微講了一下 JavaScript function 的宣告以及使用,今天將會介紹 closure 的概念在其中,讓大家了解 JavaScript 的 var 對於多重 function 的狀態,有什麼影響。
function 延伸 closure 概念 - Node.js Day 10
前面稍微講了一下 JavaScript function 的宣告以及使用,今天將會介紹 closure 的概念在其中,讓大家了解 JavaScript 的 var 對於多重 function 的狀態,有什麼影響。
內容
Closure ,對岸中文又稱為『閉包』,在原理上就是運用 JavaScript 的特性,var 的區域變數問題,在很多時候,為什麼會說 JavaScript 的 var 很重要就是在於此。
前面我們已經從各種不同變數型態,講到了 function ,這邊要結合這兩者,談談什麼叫做 closure 的概念。
先從範例開始談起,一個經典的範例就是
var a=1;
function test() {
var a = 2;
}
test();
console.log(a);
//print: 1;
前面這個範例,因為 a 一開始宣告變數初始值為 1, 之後在 function test 裡面又另外宣告了一個 a ,這個時候的變數 a 跟外面的變數 a 分別是兩個不同的變數。
在 function 裡面 var 宣告的變數,都只會在 function 中存活著,直到 function 結束為止,所以可以看到 外部的 a變數,和 function test 裡面的 a 變數,可以視為兩個不同的變數,一個是全域變數,另外一個是只存活在 function test 的區域變數。
接著再來看看這個議題,
var a=1;
function test() {
a = 2;
}
test();
console.log(a);
//print: 2;
前面的範例,a 變數因為是在 function 之外來宣告,因此在 test function 執行的時期,就可以觀察到 a 的數值會被改變,最後將 a 的數值印出之後 a 會從 1 變成 2。
傳遞變數 Closure
前面有提到 function 怎麼傳遞變數,這邊就不在描述這個部分,可是 closure 可以藉由參數傳遞的方式,達到許多有趣的效果,
function test (a) {
a += 1;
function inner() {
var b=2;
return b*a;
}
return inner();
}
console.log(test(10));
//print: 22;
這邊是屬於傳遞參數的另外一種 closure 的使用方法,從一開始 test function 就會從外面帶入 a 的這個變數,接著 a肯定會進行 + 1 ,比較模糊的部份是,最後會再 return inner();,這就意味著會去執行 inner(); 回傳出 inner 的結果給外部,最後才會將 inner 的回傳的結果給予最初呼叫 test function。
那再來看看另外一種變形,
function test (a) {
var r = inner(a);
a += 1;
function inner(a) {
var b=2;
return b * a;
}
return r;
}
console.log(test(10));
//print: 20
上面多做了一點小小的改變,function test 的最開始,多了一個 r 的變數,會直接去執行 inner,後面才執行 a += 1,而我們最後直接回傳 r 的結果,因此就只有得到最初 a 的值 *b 的原始結果,就是我們要的數值。
延伸議題
最後來講一下 closure ,在最通用的的方式,就是直接回傳 function ,
function test (a) {
return function (x) {
return x+a;
}
}
var fn = test(10);
console.log(fn(20));
//print: 30
這邊可以看到 test function 裡面的架構,最後會回傳一個匿名 function,把其他雜訊 code 先刪除,看一下整體的架構,會像是,
function test () {
return function () {
}
}
一開始傳遞給予 a 的變數近來之後,會回傳給一個 function ,
var fn = test(20);
// fn 型態會是 function
當 fn 最後就會取得一個 function,最後一步,就是去執行 fn ,而 fn 可以帶入一個變數,這個時時候,之前帶入的 test function 中的 a 變數,會繼續保存在 inner function 裡面,所以 fn 的形態就等於 inner function ,最後取得 return 的結果。
function (x) {
return x+a;
}
/*
a=10
x=20
a + x
10 + 20
*/
最後結果就會知道是, 30
後記
Closure 在 JavaScript的程式編寫當中,是一個很重要的概念,在其他語言上比較沒有這樣的使用方式,不過在 JavaScript 中經常會使用到這樣的技巧。
尤其是在 Node.js 程式當中,許多程式的腳本都會使用到這個部分,因此建議大家可以多讀起次,多多看 Open source project ,更可以了解別人怎麼使用 closure 的概念於 JS 中。