javascript閉包(closure)

練習

wikipedia對閉包的說明…

閉包可以用來在一個函式與一組「私有」變數之間建立關聯關係。在給定函式被多次呼叫的過程中,這些私有變數能夠保持其永續性。變數的作用域僅限於包含它們的函式,因此無法從其它程式碼部分進行存取。…閉包可以用來完成資訊隱藏,並進而應用於需要狀態表達的某些程式設計範式中。

因為在這個例子中閉包已經超出了建立它的函式的範圍,所以變數…返回後繼續存在。在沒有閉包的語言中,變數的生命周期只限於建立它的環境。但在有閉包的語言中,只要有一個閉包參照了這個變數,它就會一直存在。


message='message from top!';

function wait(message) {
  setTimeout(
    	//message變數超出建立的函式範圍, 會自動往上找, 在wait函式有宣告message, 在wait裡會一直存在
  		function timer() {console.log('insideLog:'+message);},
  1000);
}

wait('message for closure!');

console.log('outsideLog:'+message);	//message是抓到第一行宣告的全域變數(window.message)

//結果:
"outsideLog:message from top!"
"insideLog:message for closure!"
for (var i = 0; i <= 2; i++) {
	setTimeout(function(){console.log(i);}, 1000*i); 
}
//結果:3,3,3	
//var宣告是全域, 不是區塊內私有變數

for (let i = 0; i <= 2; i++) {
	setTimeout(function(){console.log(i);}, 1000*i); 
}
//結果:0,1,2 
//let為區塊變數, 每次執行會重新宣告, 跳出區塊就不存在

利用closure特性, 達到private及public的效果

function OrderModule() {
  let orders = 0;
  var copyRecipe = '';

  function getOrder() {
    console.log(orders);
  }

  function addOrder() {
    orders++;
  }

  return {
    getCurrentOrder: getOrder,
    addOrder: addOrder
  };
}

var foo = OrderModule();
foo.addOrder(); 
foo.addOrder(); 
foo.getCurrentOrder();

console.log(orders);

//結果:
/*
2
"Uncaught ReferenceError: orders is not defined"
*/