JavaScript 設計模式與開發實踐 - Chapter 3
Chapter 3
- 變數的範圍和生存週期。
- Closure
- High Order Function
變數的範圍和生存週期
在 JavaScript 了解變數所可以作用的範圍是相當重要的,例如以下的範例:
var a = 1;var myFunc = function() {var b = 10;console.log(a);console.log(b);};myFunc(); // 1, 10console.log(b); // ReferenceError: b is not defined
在全域的地方宣告了一個 a = 1
,myFunc
function 內宣告了一個 b = 10
的變數,在 myFunc
去
console.log(a)
為什麼會有結果呢?
原因是當 function 內部找不到變數時,會開始從程式碼的區塊的範圍往外尋找有沒有變數的存在,
而外部 console.log(b)
會造成 RefferenceError
是因為在 function 內宣告的變數只會存活在 function 區塊內,
所以有時候如果沒有將變數放在對的位置,有時候容易造成變數在參考上的錯誤。
在 ES6 中可以善用 const
和 let
來避免一些錯誤,相關文章可以參考我之前所記錄的 Beginning-ES6。
Closure
Closure 在 JavaScript 也是相當重要的概念,簡單來說 Closure 的概念是:
- Closure 是一個 function,在回傳這個 function 時,可以讓原本內部的變數繼續存活下去。
- StackOverflow - How do JavaScript closure work
function say(name) {const sayHello = `Hi! ${name}`;const myName = function () {console.log(`${sayHello}, I'm pj.`);};return myName;}const sentence = say('David');sentence(); // Hi! David, I'm pj.
在前面所提到的,在 function 內宣告的變數只能存在函式內,透過 Closure 我們可以讓它繼續存活下去。
還有一個很經典的問題,我自己也曾遇到過,假設有個情況是我們透過 onclick
來 console 該 node 的值:
會發現一個問題是,不管怎麼點都是 3,這是因為 onclick
是非同步的事件,但是在 for 迴圈內
早就已經執行完畢了,所以我們可以修正如下:
透過 Closure 的方式,我們把 i 給保留了下來,當我們 onclick
時,從內部往外尋找變數 i,會找到在
被封閉在 Closure 內的變數 i,所以就可以正確地顯示。
High Order function
High Order Function - 高階函式,意思是:
- function 可以當作參數被傳遞
- function 可以當作回傳值輸出
- function 可以當作參數被傳遞
以前在寫 JavaScript 時,有時候會看到類似這樣的 function:
function(param1, param2, callback)
以前總是不理解這個 callback
到底是做什麼用的,後來才理解原來 function 可以當作參數被傳遞。
透過以下一個簡單的 Log function 來 console 錯誤訊息的範例來解釋:
function Message(errorMessage) {console.log(errorMessage);}function Log(param1, param2, callback) {console.log(`exec1: ${param1}`);console.log(`exec1: ${param2}`);const err = new Error('Something Error');if (err) {callback(err);}}Log('doA', 'doB', Message);
Message
function 被當作參數傳到 Log
function 內使用,當有 error 時,使用 Message
function 來 console 錯誤訊息。
- function 可以當作回傳值輸出
function 當作回傳值輸出是很常見的,這代表說可以透過回傳的 function 在延續內部程式碼的執行或計算。
function addOneAndTwo(param1) {let total = 0;console.log(`param1: ${param1}`);total += param1;return function(param2) {total += param2;console.log(total);}}const calc = addOneAndTwo(1);calc(2); // 3
High Order Function 還有其他常見的一些應用,像是 Currying
。