What is closure ?
- 當一個 function return 另一個 function 時, 外層 function 的封閉環境對內層 function 環境的影響(e.g. variables … etc.)
- 當外層 function 生命週期結束, 但是內層 function 被保存下來了(e.g. 透過 return 回傳給 global 作用域), 外層 function 的作用域變數之
記憶體不會被釋放
, 持續供內層 function 使用
1 | function greet(whattosay){ |
- 外層 function : greet(), 內層 function : 被指定為 sayHi()
- 當 greet(‘Hi’) 執行完時, 由於內層 function 被回傳出來, 因此外層 function(greet()) 的作用域變數不會被釋放
- 接下來執行 sayHi() 時, 會去該記憶體位址參考值
1 | function buildFunctions(){ |
概念同上一個例子, 在 main 呼叫fs[0/1/2]() 函數時,由於 Scope 內沒有 ‘i’ 這個變數, 向
上一個Scope
(生成他的 Scope
,也就是 buildFunctions() )去找 ‘i’ , 找到了, 此時的值是'3'
, 因為已經跑完迴圈, i 停在3(跳出迴圈)
, 因此, 不管fs[0/1/2](), 都印出3Solution 1
1 | function buildFunctions2(){ |
整個函數陣列 (arr) 的生成步驟是: 先用 functionA 生成 functionB, 再 push 至 arr, 而且每一次傳入的參數 (j) 由 i 決定, 也就是說
每一次生成函數時的 j 值都不一樣了
, 各自為獨立的執行環境. 因此呼叫 fs2[0]() 時, 沒有 j, 向上一層找, 找到 j, 且值是 ‘0’; 呼叫 fs2[1]() 時, 沒有 j, 向上一層找, 找到 j, 且值是 ‘1’; 也就是每一次都是獨立的執行環境
, 所以 j 的值不同.Solution 2
- 利用 ES6 -
let
作用域的特性- 當 let 宣告在 for 迴圈之中時,
每一個 iterations 自成一個作用域
- 因此每一個 i 在各自 iterations 是
個別有自己的記憶體空間的
, 互不影響1
2
3
4
5
6
7
8
9
10
11
12
13
14function buildFunctions2(){
var arr = [];
for(let i=0; i<3; i++){
arr.push(function(){ console.log(i)});
}
return arr;
}
var fs2 = buildFunctions2();
fs2[0]();
fs2[1]();
fs2[2]();
- 因此每一個 i 在各自 iterations 是
- 當 let 宣告在 for 迴圈之中時,
- 利用 ES6 -
參考文獻
- Online Coures - JavaScript: Understanding the Weird Parts : Ch47 - closure
- 另一種方式介紹 JavaScript 閉包