JavaScript Weird Part (27) - 函數陳述句與函數表示式

了解函數就是物件後,接著要實際運用這個觀念。開始之前,我們要先了解函數陳述句 (Function Statements) 與函數表示式 (Function Expressions) 的用法差異。

表示式

表示式是程式碼的單位,會形成一個值 (A unit of code that results in a value)
直接地說,任何表示式最終都會創造一個值,而這個值不一定要儲存在某個變數。

舉例來說,我們宣告一個變數 a,並且打開開發者工具輸入以下

1
2
a = 3;
//3

上面是一個簡單的表示式,我們透過等號運算子把 3 賦與給變數 a,執行它,得到回傳的結果。所以表示式也可以這樣寫

1
a = { greet: "Hi" };

陳述句

當我們提到陳述句,陳述句表示「做某件事情」。

1
2
3
4
var a;

if (a === 3) {
}

a===3 就做某件事情。在 if 陳述句的括號內,必須放入表示式,因為會形成一個值,這樣這個陳述句才能運作。陳述句本身不會回傳任何值。

像是我不能這麼做,這不會有任何效用,因為沒有任何值會回傳給變數 b

1
2
3
var b=if(a===3){

}

結論:陳述句會做其他事情,表示式則回傳值

函式表示式與函式陳述句的差異

1
2
3
function greet() {
console.log("hi");
}

函式陳述句

這是一個簡單的函式陳述句,在創造執行環境的時候,這個函式被放進記憶體中,但這只是陳述句,所以不會回傳任何的值,直到函式被呼叫執行。

雖然函式陳述句不會回傳任何值,但它會有提升 (hoisting) 現象,所以可以在任何地方取用它

1
2
3
4
greet();
function greet() {
console.log('hi');
}

函式表示式

宣告一個 anonymousGreet 變數並且使用等號運算子,然後在右側使用函式陳述句。

記得「函數就是物件」,所以「建立一個物件,並且設定它等於這個變數」,這個變數也就是它在記憶體中指向的位置。

我們已經有一個已經知道函式物件位址的變數 anonymousGreet ,所以等號右邊的陳述句可以改寫成這樣,稱為匿名函式。

1
2
3
var anonymousGreet = function () {
console.log('hi');
}

如何觸發函式表示式

我們需要指向那個物件,告訴它要執行程式,像這樣

1
anonymousGreet();

因為變數已經知道函數記憶體的位址,所以只要加上 (),就可以觸發函式。

但是因為函式表示式的提升 (hoisting) 現象,造成一個值得注意的問題。如果我們把程式碼改寫成這樣

1
2
3
4
anonymousGreets();
var anonymousGreets = function() {
console.log('Hi');
}

結果變這樣,為什麼?

還記得當執行環境被創造,創造執行階段會把函式陳述句以及變數都放入記憶體,變數被賦予初始值 undefined ,然後逐行執行程式碼。

於是程式的第一行是「anonymousGreets();」,但此時仍未賦予變數值,變數的值仍然是 undefined 。自然的,錯誤便會告訴我們 undefined 不是函式,它沒辦法被使用 () 呼叫執行。

1
2
3
var anonymousGreets = function() {
console.log('Hi');
}

直到上述這行程式碼,anonymousGreets 變數的值才被賦予函式物件。

所以函式表示式不受到提升 (hoisting) 影響。

傳入函式表示式做為參數

記得我們說的函式是物件,函式表示式可以馬上創造函式物件,因此我們可延伸出以下寫法:

1
2
3
4
5
6
7
function log(a){
console.log(a);
}

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

我們立即創造了一個函式物件,在裡面寫了一些程式碼。然後把這個函式物件當成參數傳入 log 函式內

不過這樣只是印出函式物件的內容而已,但透過這樣的觀察得知「一級函式可以很快地被創造、使用,且變數也可以設值成為一級函式」

我們結合上述這些並做些修改:

1
2
3
4
5
6
7
8
9

function log(a){
a();
}

var anonymousGreets = function(){
console.log('hi');
}
log(anonymousGreets); // hi

因為我們傳入 log 函式的參數為函式物件,所以變數 a 參照到了這個函式物件。同樣地,要呼叫執行函式僅需要加上 () 即可。

本例來看,我使用函式表示式,接著把這個函式傳入當作另一個函式的參數,這樣另一個函式就可以使用這個函式表示式,這就是我們提到的一級函式的觀念「可以將函式傳入別處」。

可以把函式給另一個函式,就像使用變數一樣,這樣的做法也稱為函式程式語言 ( functional programming )。

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2020 CYC'S BLOG All Rights Reserved.

UV : | PV :