談 JavaScript 表達式與陳述式的差異:學習 React 帶來的啟發

更新 發佈閱讀 13 分鐘

面對 JavaScript 核心觀念時,總是感覺似懂非懂,於是就這樣不求甚解地繼續學習程式。但該面對的最終還是得面對,有些東西總會像鬼一樣,沒解決就會陰魂不散的回來,表達式 (expression) 與陳述式 (statement) 這兩個好兄弟就是其中之一。

還好有 Josh Comeau 深入淺出的文章,把我從五里霧中拉了出來,應 該 吧。這篇文章將以此基礎,就我的理解加其他輔助資料撰寫而成,如有錯誤還煩請指教。那就廢話少說開始吧。

Photo Credit: Ferenc Almasi, Unsplash

Photo Credit: Ferenc Almasi, Unsplash


什麼是表達式?

如果要說表達式是什麼?最簡單的回答就是「能夠產生值的程式碼」,它可以是:

  • 任何的資料型別,像是
    • 數字: 168
    • 字串:"string"
    • 布林:truefalse
    • 陣列:["arr", "ray", "yee"]
    • 物件:{ type: "object" }
  • 運算子產生的結果,常見的有
    • 賦值運算子:=
      → 回傳「所賦予的值」
    • 算數運算子:+-*/%
      → 回傳「運算後的結果」
    • 比較運算子:><=====
      → 回傳「布林值」
    • 邏輯運算子:||&&!
      • ||:回傳「布林值」(「或」的判斷),或「第一個真值」
      • &&:回傳「布林值」(「且」的判斷),或「第一個假值」
      • !:回傳「翻轉後的布林值結果」
    • 條件(三元)運算子:hasValue ? "expressions" : "statements"
      → 依據條件真假(hasValue 處),決定回傳值:
      若為,回傳「冒號之前的值」;若為,回傳「 冒號之後的值」
  • 執行函式後產生的結果,以下有幾種情況:
// 1. 有明確的回傳值
function execFnHasReturn() {
console.log("This function will return something after execution");
return "I am returned value";
}
console.log(execFnHasReturn()); // 執行後回傳 "I am returned value"

// 2. 有 return 但沒有回傳值
function execFnEmptyReturn() {
console.log("This function will return 'undefined' value after execution");
return;
}
console.log(execFnEmptyReturn()); // 執行後回傳 undefined

// 3. 沒有 return
function execFnNoReturn() {
console.log("This function will return 'undefined' value after execution");
}
console.log(execFnNoReturn()); // 執行後回傳 undefined

→ 無論回傳值是否為 undefined,都不改執行函式是表達式的事實

  • 調用方法的結果,方法本質上也是函式的一種,回傳值會依方法而定:
["apple","banana"].push("orange");       // 回傳 3,新增項目後陣列的長度​
[1, 2, 3].forEach(i => console.log(i)); // 回傳 undefined
[3, 1, 2].sort() // 回傳 [1, 2, 3],修改後的陣列
"yee".toUpperCase() // 回傳 "YEE"
  • 其他:變數、正規表達式、函式表達式……


看了這麼多表達式的型態,可以歸納幾個重點:

  1. 表達式可以透過運算子,形成更複雜的表達式,例如:
    1. 88 / (1.88 * 1.88)
      88 / (1.88 * 1.88)(1.88 * 1.88)881.88 都是表達式
    2. hasValue ? "expressions" : "statements"​
      hasValue"expressions""statements"​ 都是表達式
  2. 會回傳值,即便該值是 undefined,也是表達式


什麼是陳述式?

JavaScript 是由一系列陳述式組成,陳述式不會產生值,它的作用在於告訴瀏覽器「該執行什麼動作」以及「控制程式的流程走向」,主要分為以下幾種:

  • 宣告:告訴瀏覽器要為宣告的內容分配記憶體空間
    • 變數的宣告:用 varletconst 關鍵字來宣告變數
    • 函式的宣告:用 function 來宣告函式
    • 類別的宣告:用 class 來宣告類別
  • 流程控制:告訴瀏覽器執行程式碼的流程該怎麼走
    • 條件判斷:if...elseswitchwhile/do...while
    • 迴圈執行:for、 ​for...infor...of
    • 語句中斷、回傳或跳轉:return(throw)、breakcontinue
    • 例外處理:try...catch(& finally)
  • 模組相關:importexport
  • 其他:debugger(中斷執行)、async/await(非同步處理)、{ }(區塊)…

陳述式透過這些關鍵字建立出一個敘述的邏輯架構,但要有內容才是完整的陳述句,而這些內容,則需要靠表達式來提供,例如,

// if 陳述式
if (/* 表達式 */) {
//...
}

// 範例
if (age >= 18 && hasID) {
// ...
}

// 迴圈陳述式
for (/* 初始化;條件;更新 */) {
// ...
}
// -> 條件、更新須為表達式
// -> 初始化可用變數宣告或表達式,以 let 宣告可限定作用域

// 範例
for (let i = 0; i < array.length; i++) {
// ...
}

// switch 陳述式
switch (/* 表達式 */) {
case /* 表達式 */:
// ...
}

// 範例
switch (status) {
case "success":
// ...
}

同時,我們可以透過宣告變數,將表達式的值存入該變數之中:

let num = 168;
let str = "string";
let isBool = true;
let arr = ["arr", "ray", "yee"];
let obj = { type: "object" };
let text = "yee".toUpperCase()


學習 React 帶來的啟發

撰文當下,我對 React 的理解還不夠深入,不過在學習的過程中,似乎讓我對表達式與陳述式的差別更加清明了。

在 React 中,我們會透過一種叫做 JSX 的語法,在 JavaScript 中撰寫 HTML 的結構。JSX 能夠讓我們可以在 HTML 的結構中,透過大括號 {} 將 JavaScript 程式碼插入 HTML 裡。

不過,這個大括號並非毫無限制,我們並沒有辦法隨心所欲地放入任何的 JavaScript 程式碼,我們看看下方兩個 JSX 的例子,同樣是處理條件邏輯,但其中一個會出錯:

  • 大括號內用 if...else 語句(陳述式):會出現語法錯誤
function DisplayExamResult({ examScore }){
return (
<div>
{if (examScore >= 60){
return "Congrats! You passed!"
} else {
return "What a pity, you failed!"}}
</div>
);
}
  • 必須使用「三元運算子」(表達式)處理條件的邏輯:
function DisplayExamResult({ examScore }){
return (
<div>
{examScore >= 60 ? "Congrats! You passed!" : "What a pity, you failed!"}
</div>
);
}

一樣是條件邏輯,我們只能在大括號內放入表達式,為什麼呢?


JavaScript 作為一種……語言?

拿 Comeau 的比喻來形容(我也覺得這個比喻極讚!),JSX 的大括號 {} 就像是 HTML 模板中的插槽,我們需要在這個插槽中放入「表達式」,而不是「陳述式」。因為只有表達式才會產生具體的值,才能變成實際的東西被渲染到畫面上。

雖然可能不是很精確,不過用英文基礎的「主詞-動詞-受詞」(S-V-O) 句型來說,如果挖空主詞、受詞的位置,這個空格可以用很單純的名詞填補,你也可以套上形容詞、甚至形容詞子句讓這個名詞變得更加複雜,但最終你填上的東西,還是得屬於名詞類,因為在英文文法中,主詞、受詞只能是名詞類的東西。

### S V O 句型
The woman wrote a program.

### 將 S、 O 挖空
{ S } wrote { O }​

### ​用更複雜的 S、O 撰寫
The elegant **woman** you saw yesterday
wrote
a complicated **program** by herself to change people's lives.

表達式的撰寫方式可能有上百種,但我覺得它所傳出來的「值」就有點像是這種概念。回到 JSX 的大括號裡為什麼不能放 if...else 語句的問題,用英文句型的思考來回答,就是詞類不相符。

有了這個感覺,突然好像對我們時常稱呼 JavaScript 的名詞——程式語言——更加有所體悟。

為什麼會稱 JavaScript 為「語言」呢?相對的,HTML、CSS 就好像沒那麼常被這樣形容。就我穿鑿附會的想像,原因可能是:

JavaScript 和人類語言一樣,能夠歸納出固定的語法結構和規則

我想到的是,寫 JavaScript 時,之所以像是與瀏覽器溝通,也許就是表達式與陳述式相互作用的結果。陳述式提供句子的結構,控制語意的走向;而表達式則像是句子中的片語,可以產生一個具體的值,填補結構中的空白,才能賦予程式碼意義,進而向瀏覽器表達出我們的目的。


總結

以免被我的老人廢話給稀釋重點,最後再來複習一下表達式與陳述式的主要特色吧:

  • 表達式
    • 執行時會產生值
    • 用於預期會是值的地方(插槽),例如 JSX 的大括號內、變數賦值,以及函式的參數等等
    • 可以與其他表達式結合,產生更複雜的表達式
  • 陳述式
    • 告訴瀏覽器執行特定動作
    • 形塑程式碼的結構,控制程式碼流程走向
    • 經常與表達式一起使用,但本身不會產生值


希望這篇文章能夠幫助到你,如有錯誤也煩請指教,感謝你的閱讀。


參考資料

留言
avatar-img
留言分享你的想法!
avatar-img
肝 code 人生
0會員
3內容數
2024 年 7 月開始的「肝 code 人生」,2025 年 1 月撰寫第一篇程式筆記
你可能也想看
Thumbnail
這篇內容,將會講解什麼是表達式(Expression),什麼是陳述式(Statement)。有了這些概念,各位會更容易理解,要如何設計程式碼。
Thumbnail
這篇內容,將會講解什麼是表達式(Expression),什麼是陳述式(Statement)。有了這些概念,各位會更容易理解,要如何設計程式碼。
Thumbnail
這些章節的目的是為了介紹JavaScript中的各種數據類型,包括基礎類型和物件類型,以及如何將數據從一種類型轉換為另一種類型。此外,還介紹了如何創建自定義類型,以及如何使用JavaScript中的陣列、集合和字典。
Thumbnail
這些章節的目的是為了介紹JavaScript中的各種數據類型,包括基礎類型和物件類型,以及如何將數據從一種類型轉換為另一種類型。此外,還介紹了如何創建自定義類型,以及如何使用JavaScript中的陣列、集合和字典。
Thumbnail
JS 資料型別分為兩大類,原始型別 (Primitive values) 和物件型別 (Objects)。
Thumbnail
JS 資料型別分為兩大類,原始型別 (Primitive values) 和物件型別 (Objects)。
Thumbnail
在剛開始寫 JavaScript 可能大多數的人不會特別意識到 JavaScript 的型別系統有什麼特別之處,我是在看完 Youtube 上 CS50 的課程,才理解到在不同的程式語言中,會因為語言的特性而有不同的系統,JavaScript 就是偏向比較特別的那一種。
Thumbnail
在剛開始寫 JavaScript 可能大多數的人不會特別意識到 JavaScript 的型別系統有什麼特別之處,我是在看完 Youtube 上 CS50 的課程,才理解到在不同的程式語言中,會因為語言的特性而有不同的系統,JavaScript 就是偏向比較特別的那一種。
Thumbnail
React 是開發網頁、手機前端最流行的 JavaScript 套件之一。React 由 Meta 開發,使開發人員能夠創建可重覆使用的元件來完成前端頁面。JSX 也是目前我們比較常看到的 React 寫法 ,因此接下來會介紹,JSX 是什麼?JSX 語法以及使用 JSX 建構 React 元件。
Thumbnail
React 是開發網頁、手機前端最流行的 JavaScript 套件之一。React 由 Meta 開發,使開發人員能夠創建可重覆使用的元件來完成前端頁面。JSX 也是目前我們比較常看到的 React 寫法 ,因此接下來會介紹,JSX 是什麼?JSX 語法以及使用 JSX 建構 React 元件。
Thumbnail
今天會接續介紹 JS ES6 其他新穎的語法,物件解構(Object Destructuring)物件語法強化(Object Literal Enhancement)陣列解構(Array Destructuring)延展運算子(Spread Operator)。
Thumbnail
今天會接續介紹 JS ES6 其他新穎的語法,物件解構(Object Destructuring)物件語法強化(Object Literal Enhancement)陣列解構(Array Destructuring)延展運算子(Spread Operator)。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News