2016年3月10日

[筆記] 進一步談JavaScript中函式的建立─function statements and function expressions

img
圖片來源:Udemy
在這堂課中,我們會說明 function statements 和 function expressions 這兩種不同建立函式的方式,這是兩個許多新手在學 JavaScript 會有些搞不懂的地方。
在進入到 function 的部分前,先來看看表達式(expressions)和陳述句(statements)有什麼不同吧。

表達式(Expressions)和陳述句(Statements)的差異

表達式(Expressions)

Expressions 指的是輸入後能夠直接回傳值的一串程式(a unit of code that results in a value),我們一般可能會把它存成一個變數,但是它不一定要被存成一個變數
簡單來說,只要你輸入的那串程式執行後能直接回傳一個值,那麼它就是個 expression。
舉例來說,在瀏覽器的 console 中輸入 a = 3 時,它會直接回傳 3 這個值;輸入 2 + 3 的時候,它會直接回傳 5;輸入 a = { } 的時候,它會回傳一個為物件的值。這種輸入一段程式後,會直接取得回傳一個值的程式內容,我們就稱為 Expressions。
Imgur

陳述句(Statements)

那麼陳述句(Statements)是什麼呢?
我們來看看這段程式:
if (a === 3) {
  console.log('Hello');
}
在這段程式中 a === 3 是一個表達式(expression),因為它可以直接回傳值(即,truefalse);而 if 這個指令,則是一個 statement,因為它不會直接回傳一個值,我們也不能將它指定為一個變數:
// ❌ 錯誤寫法
const b = if (a === 3) {
  console.log('Hello');
}

Function Expressions 和 Function Statements

在 JavaScript 中,Function 就是物件的一種,它可以透過 Expression 或 Statements 的方式加以操作。

Function Statements

首先,我們來看一下Function Statements:
// Function Statements
function greet() {
  console.log('Hi');
}
這是一串 Function Statements,它不會直接回傳任何的值。Function Statements 的特色在於,它在程式執行的最開始,該函式就會透過 hoisting 先被儲存在記憶體中(如果不清楚 Hoisting 的概念,可以參考:筆記 - 談談Javascript 中的 Hoisting),也就是說我們可以在執行這段程式前,就去呼叫這個函式來使用而不會出現任何的錯誤,像是這樣:
/* Function Statements will be hoisted */
greet();   // 'Hi'

function greet() {
  console.log('Hi');
}
由於在 JavaScript 中 function 就像物件一樣,用物件的概念來理解函式的話,這個函式屬性 name 的值是 greeting,這個函式 code 屬性的值為 console.log('hi')
imgur
當我們要執行這個函式的時候,只要輸入 greet() 就可以了。
如果我們用 console.log(greet),會得到這個函式的程式內容(code),所以如果我們想要執行這個函式,就在最後面再加上 ( ) 就可以了:
Imgur

Function Expressions

再來看一下 Function Expressions,我們先前有提過在 JavaScript 中 Function 就是物件的一種,所以我們可以把它存在一個變數中。以下面的程式碼為例:
// Function Statements
const sayHello = function() {
  console.log('Hello');
};
這裡的 function(){ ... } 這段就是 Function Expression,現在我們則把這個函式表達式的值存在 sayHello 這個變數內。
從物件的角度來看函式的話,在這個例子中,就是先建立了一個函式,但在這個函式的 name 屬性並沒有給它值(因為我們在括號前面並沒有給任何名稱),之所以可以這麼做是因為,我們在 function expression 前面已經把它指定到一個變數(sayHello)了,所以可以直接用這個變數名稱來指稱這個函式。對於這種 name 屬性沒有值的函式,我們可以稱作匿名函式(anonymous function 或 function literal)
imgur
圖片來源:Udemy - JavaScript: Understanding the Weird Parts,此圖的函式名稱為anonymousGreet
同樣的,如果我們想要執行這個函式,一樣輸入 sayHello() 就可以了。
當我們在瀏覽器的開發者工具中輸入 console.log(sayHello) 時,我們一樣會得到這個函式的程式內容,因此,若我們想要執行這段程式內容,同樣只要在最後面加上( ) 就可以了:
Imgur
然而,和 Function Statements 不同的地方是,因為在一開始執行程式初期,只會先建立並儲存變數名稱到記憶體中,也就是只會儲存 sayHello 到記憶體中,但程式內容不會一併儲存進去(這時候 sayHello 的值會是 undefined),所以如果我在 function 定義前面就想要執行它的話,即會出現錯誤訊息:
// ❌ 錯誤寫法
// ReferenceError: Cannot access 'sayHello' before initialization

sayHello();   // 使用 Function Statements 的話不能在定義前呼叫它

// Function Statements
const sayHello = function() {
  console.log('Hello');
};
imgur

再來看一點特別的吧 - 函式中的函式

看一下這段程式。先建立一個函式,name 屬性的值是 logcode 的內容是 console.log(a),其中 a 是這個函式的參數。
接著,我分別去執行 log(...),會分別得到如下註解的結果:
function log(a) {
  console.log(a);
}

log(3); // 3
log('Hello'); // 'Hello'
log({ Country: 'Taiwan' });   // { Country: 'Taiwan' }
同樣地,我們也可以先把這些值指定成一個變數,然後再丟到函式當中,會得到一樣的結果:
function log(a) {
  console.log(a);
}

const number = 3;
log(number); // 3

const hello = 'Hello';
log(hello); // 'Hello'

const country = { Country: 'Taiwan' };
log(country); // { Country: 'Taiwan' }

如果這時候我的值是函式的話呢

假設我們在 log() 裡面,放入一個 function expressions,而且是一個匿名函式(anonymous function),這時候我們等於是直接創造了一個函式來使用(create the function on the fly):
log(function() {
  console.log('Hello');
});
如果看不太懂的話,可以想成這樣會比較容易理解:
const anonymousFunction = function() {
  console.log('Hello');
};

log(anonymousFunction);
這時候會回傳這樣的結果:
Imgur
那麼,如果我們希望能夠直接執行該函式,我們可以將 log( ) 做一下簡單的修改就可以了:
function log(a) {
  a();
}

const anonymousFunction = function() {
  console.log('Hello');
};

log(anonymousFunction);   // Hello
這樣,就可以在不用建立函式的情況下,直接去執行一個匿名函式。
由於 JavaScript 非同步的特性,若想要確保程式執行的順序,常常會使用到回呼函式(callback function)這種方式,它內部的做法其實也就是把函式傳入另一個函式中去呼叫。
這種傳入一個函式到另一個函式中去呼叫的方式在 JavaScript 中經常會使用到,特別是回呼函式(callback function)。

程式範例

// Function Statements
function greet() {
  console.log('Hi');
}

// Function Expressions
var sayHello = function() {
  console.log('Hello');
};

function log(a) {
  a();
}

log(function() {
  console.log('Hello');
});

資料來源

Udemy - JavaScript: Understanding the Weird Parts- Function Statements and Function Expressions

0 意見:

張貼留言