JavaScript 核心觀念(11)-運算子、型別與文法-陳述式與表達式
前言
陳述式 vs 表達式是最容易搞不清楚的觀念,包含我自己也是。
陳述式與表達式
基本上你可以透過 MDN 文件了解 JavaScript 的陳述式與表達式有那些,例如
陳述式有
var
、let
、const
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 | if(true) { |
你會發現只要是陳述式它就只會回傳 undefined
反之表達式就不同,表達式必定會回傳一個結果一個值
1 | aa = 'Ray'; |
題外話一下,我們常在開發使用的 setTimeout
以及 setInterval
也是屬於表達式
1 | setTimeout(function(){}, 10000); // 1000 = 1 秒 |
此外陳述式與表達式還有一個特徵可以辨別,也就是陳述式無法被變數儲存,因為陳述式不會回傳值的關係
1 | a = if (true) {}; |
函式陳述式
接下來講講另一種的陳述式與表達式,函式在宣告時其實也有分為兩種廣義的宣告方式,第一種就是所謂的函式陳述式
1 | function fu() { |
基本上函式陳述式在宣告時,並不會回傳結果,而是與前面相同,僅會回傳 undefined
,此外上面的函式陳述式又稱之為具名函式陳述式。
函式表達式
函式表達式通常會宣告一個變數並搭配等號運算子以及一個函式,而這個就是所謂的函式表達式
1 | var fu = function() {} |
而這個宣告函式的方式又稱之為匿名函式表達式,雖然你在 Chrome 中,輸入他一樣會回傳給你一個 undefined
,但實際上因為這個函式沒有 name
所以會被回傳儲存在 fu
的變數內,而函式表達式最大的特徵在於他不會受到提升的影響,因此若你在函式表達式之前呼叫,它就會出現錯誤訊息
block 與物件實字
最後額外講一個特別狀況,在 JavaScript 中有一個 block,也就是 {}
, block 在 MDN 中也是屬於陳述式,因此可以這樣寫
1 | { |
但是若是改寫成物件實字則是使用「:
」來區分屬性與值
1 | { |
而這邊兩者最大差異在於物件實字是一個表達式,因此表達式我們可以儲存進變數內中
1 | var a = { |
但若是 block 則是不行,因為他是一個陳述式
1 | var b = { |
最後的結論就是只要會回傳結果或是值,那麼就是屬於表達式,若不會那麼就是陳述式。
混合式
這個名稱其實算是我自創的,主要是要說明 var a = 1;
與 var a = function() {}
相信看完上面有很多人都會說「var a = 1;
應該算是表達式才對,怎麼會歸類為陳述式?它不是有賦值行為嗎?」
沒錯,所以你要說他是表達式也是正確的,其主要原因是,大多 JavaScript 都是屬於混合式(表達式 + 陳述式),這邊舉例來講,我們知道 if
判斷式是一個陳述式,但判斷式中主要是接受表達式的,因此可以這樣撰寫
1 | var a; |
透過表達式的回傳,我們可以讓判斷式進入顯示 True
,因此通常我們都會廣義地稱 var a = 1;
是陳述式以及 var a = function() {}
是表達式。
如果真的要計較的話,那麼就應該要說混合式(表達式 + 陳述式),因為它同時有陳述式 var a;
與 a = 1;
的特性,但通常會建議分開來理解因為這樣子比較不會搞混自己。