JavaScript 核心觀念(11)-運算子、型別與文法-陳述式與表達式

前言

陳述式 vs 表達式是最容易搞不清楚的觀念,包含我自己也是。

陳述式與表達式

陳述式與表達式

基本上你可以透過 MDN 文件了解 JavaScript 的陳述式與表達式有那些,例如

陳述式有

  • varletconst
  • if...else
  • for

    等等

而表達式則是因為太多無法列出,基本上表達式經常會與運算子搭配並回傳結果。

陳述式 (Statement)

基本上陳述式是不會回傳結果的,在這邊你應該會覺得很奇怪,剛才不是說表達式通常會搭配運算子並回傳結果嗎?那麼變數宣告的 var a = 1; 有回傳一個 undefined 為什麼不算是一個表達式呢?而且他也有 = 運算子,這樣子不算是表達式嗎?

相信很多人對於「變數宣告」為什麼是一個陳述式感到疑惑,陳述式最簡單的觀念來自「它只會靜靜躺在那邊等你呼叫,最大特徵在於不會回傳任何的結果,但是陳述式必定會先執行過一次」,其主要原因在於它要先確定語法作用域。

因此若在 Chrome 上的 console 輸入 var a = 1; 卻會回傳 undefined 的原因在於變數宣告時,JavaScript 會先執行過一次,因為它要替這個變數準備一個記憶體空間,並將記憶體空間與變數名稱對應,但並不會回傳結果,因此變數宣告才會回傳給你一個 undefined,而在這邊的 undefined 只是告訴你我已經替這個變數宣告準備好了記憶體空間而已。

表達式 (Expression)

表達式又稱之為運算式,也可以稱為表示式,最間單的觀念理解在於它會回傳一個值,例如當你輸入 1+1 它會在底下回傳一個 2,而這就是表達式

表達式

在 MDN 中有說明運算式的幾個特徵

算數: 解析出數字, 例如 3.14159. (通常使用 算術運算子.)
字串: 解析出字串, 例如 “Fred” or “234”。 (通常使用 字串運算子.)
邏輯: 解析出 True 或 False (通常與 邏輯運算子 相關。)
主流運算式: JavaScript 基本的關鍵字及運算式。
左側運算式: 左側是指定值的對象。

因此通常表達式會搭配一些運算子,但表達式最簡單的便是觀念在於「會回傳一個結果 or 一個值」,因此當我們輸入 qq = 'Ray' 它會回傳一個 'Ray' 這就是表達式。

表達式

而表達式的重點觀念在於運算子,因此等號是一個表達式,它會將值賦予到 qq 並回傳結果,因此我們這邊可以回顧一下變數宣告中的 var a = '11'; 為什麼會回傳 undefined,前面有說過變數宣告會回傳 undefined 的原因在於它準備好一個空間給記憶體給變數使用,接下來讓我們看一下其他陳述式通常會發生什麼事情

1
2
3
4
5
6
if(true) {
}

function fu() {}

for(var i; i< 10;i++) {}

你會發現只要是陳述式它就只會回傳 undefined

陳述式

反之表達式就不同,表達式必定會回傳一個結果一個值

1
2
3
4
aa = 'Ray';
1+1;
a = true;
b = function () {}

表達式

題外話一下,我們常在開發使用的 setTimeout 以及 setInterval 也是屬於表達式

1
2
setTimeout(function(){}, 10000); // 1000 = 1 秒
setInterval(function(){}, 10000);

setTimeout&setInterval

此外陳述式與表達式還有一個特徵可以辨別,也就是陳述式無法被變數儲存,因為陳述式不會回傳值的關係

1
a = if (true) {};

陳述式無法被儲存到變數內

函式陳述式

接下來講講另一種的陳述式與表達式,函式在宣告時其實也有分為兩種廣義的宣告方式,第一種就是所謂的函式陳述式

1
2
3
function fu() {

}

基本上函式陳述式在宣告時,並不會回傳結果,而是與前面相同,僅會回傳 undefined,此外上面的函式陳述式又稱之為具名函式陳述式。

函式表達式

函式表達式通常會宣告一個變數並搭配等號運算子以及一個函式,而這個就是所謂的函式表達式

1
var fu = function() {}

而這個宣告函式的方式又稱之為匿名函式表達式,雖然你在 Chrome 中,輸入他一樣會回傳給你一個 undefined,但實際上因為這個函式沒有 name 所以會被回傳儲存在 fu 的變數內,而函式表達式最大的特徵在於他不會受到提升的影響,因此若你在函式表達式之前呼叫,它就會出現錯誤訊息

函式表達式

block 與物件實字

最後額外講一個特別狀況,在 JavaScript 中有一個 block,也就是 {}, block 在 MDN 中也是屬於陳述式,因此可以這樣寫

1
2
3
{
var a = 'Ray';
}

但是若是改寫成物件實字則是使用「:」來區分屬性與值

1
2
3
{
a: 'Ray',
}

而這邊兩者最大差異在於物件實字是一個表達式,因此表達式我們可以儲存進變數內中

1
2
3
var a = {
a: 'Ray',
};

但若是 block 則是不行,因為他是一個陳述式

1
2
3
var b = {
var a = 'Ray';
}

block 與物件實字

最後的結論就是只要會回傳結果或是值,那麼就是屬於表達式,若不會那麼就是陳述式。

混合式

這個名稱其實算是我自創的,主要是要說明 var a = 1;var a = function() {}

相信看完上面有很多人都會說「var a = 1; 應該算是表達式才對,怎麼會歸類為陳述式?它不是有賦值行為嗎?」

沒錯,所以你要說他是表達式也是正確的,其主要原因是,大多 JavaScript 都是屬於混合式(表達式 + 陳述式),這邊舉例來講,我們知道 if 判斷式是一個陳述式,但判斷式中主要是接受表達式的,因此可以這樣撰寫

1
2
3
4
var a;
if(a = true) {
console.log('True'); // True
}

透過表達式的回傳,我們可以讓判斷式進入顯示 True,因此通常我們都會廣義地稱 var a = 1; 是陳述式以及 var a = function() {} 是表達式。

如果真的要計較的話,那麼就應該要說混合式(表達式 + 陳述式),因為它同時有陳述式 var a;a = 1; 的特性,但通常會建議分開來理解因為這樣子比較不會搞混自己。

參考文獻