Learning Objectives
- 說明運算式、運算子與運算元的關係,使用算術、指定與遞增遞減運算子
- 用比較運算子比較數字與字串,說明 == 與 === 的差別,並一律使用 ===
- 說明 &&、|| 的短路求值與回傳值,用 ?? 與 ?. 處理沒有值的情況
- 依運算子優先順序預測運算式的結果,必要時用括號表達意圖
運算式、運算子與運算元
運算式(expression)是一段會算出一個值的程式碼,例如 x + 1。裡面的 + 是運算子(operator),
x 和 1 是被運算的運算元(operand)。依照運算元的數量分成三種:
| 種類 | 運算元 | 例子 |
|---|---|---|
| 一元運算子 | 1 個 | -x、!ok、x++、typeof x |
| 二元運算子 | 2 個 | x + y、a === b、a && b |
| 三元運算子(條件運算子) | 3 個 | score >= 60 ? '及格' : '不及格' |
x = x + 1 是合法的運算式;x = 1 + 少了一個運算元,是語法錯誤。這一課依序介紹算術、比較(關係)與邏輯運算子。
算術與指定運算子
| 運算子 | 意思 | 例子 | 結果 |
|---|---|---|---|
+ - * / |
加減乘除 | 7 / 5 |
1.4(不會只取整數) |
% |
餘數 | 7 % 5 |
2 |
** |
次方(ES2016) | 2 ** 3 |
8 |
+= -= *= /= %= |
運算後指定回去 | a += 5 |
等於 a = a + 5 |
+ 是唯一會處理字串的算術運算子:只要有一邊是字串,就變成字串連接,'7' + 5 是 '75'。
其他算術運算子會把字串轉成數字:'7' - 5 是 2、'7' * '2' 是 14,轉不成數字就是 NaN。
算術運算子與字串
投影片 Lab01 的延伸。第 4 行是 9÷3(1+2) 的寫法;第 6、7 行比較 + 和其他運算子遇到字串時的差別。最後看 a 經過 += 與 %= 之後變成多少。
++ 放前面與放後面
x++ 和 ++x 都會讓變數加 1,差別在運算式本身的值:放後面先取原本的值再加,放前面先加再取值。看第 3 行與第 7 行執行後,右邊 y 和 n 的值。
比較運算子:== 與 ===
比較運算子的結果一定是布林值 true 或 false:>、<、>=、<=、==、!=、===、!==。
注意 = 是指定,==、=== 才是比較。
=== 嚴格相等 |
== 寬鬆相等 |
|
|---|---|---|
| 型別不同時 | 直接 false |
先轉換型別再比較 |
2 === '2' / 2 == '2' |
false |
true |
0 === false / 0 == false |
false |
true |
null === undefined / null == undefined |
false |
true |
== 的轉換規則很多,結果常出乎意料('' == 0 是 true、[] == false 也是 true)。一律使用 === 和 !==,
需要轉換時自己先轉(例如 Number(input) === 6),程式的意思才清楚。
其他比較的規則:
- 字串和字串比較時,依字元的 Unicode 編碼逐字比較(字典順序):
'apple' < 'banana'是true,但'10' < '9'也是true(先比'1'和'9')。要比大小的數字,記得先轉成數字。 NaN和任何值比較都是false。in檢查物件有沒有某個屬性名稱,對陣列檢查的是索引:0 in ['a']是true,'a' in ['a']卻是false。要檢查陣列有沒有某個值,用arr.includes('a')。instanceof檢查物件是不是某個類別建立的,例如new Date() instanceof Date是true(j27、j28 會介紹)。
比較運算子
投影片 Lab02 的題目都在這裡。每一行左右兩個結果對照著看:差別通常就在 == 和 ===。
想一想:算術與比較
下面的程式會印出什麼?
console.log('3' + 2, '3' - 2);
下面的程式會印出什麼?
let i = 1;
const j = i++ + ++i;
console.log(i, j);
下面的程式會印出什麼?
console.log('10' < '9', 10 < '9');
邏輯運算子與短路求值
a && b:而且(and),兩邊都是 true,結果才是 truea || b:或者(or),至少一邊是 true,結果就是 true!a:不是(not),把 true 變成 false、false 變成 true
兩個重要的細節:
- 短路求值(short-circuit evaluation):
&&的左邊已經是 false,結果一定是 false,右邊根本不會執行;||的左邊已經是 true,右邊也不會執行。 &&、||回傳的是其中一個運算元本身,不一定是true/false:a && b:a 是 falsy 就回傳 a,否則回傳 b。所以2 && 1是1、0 && 2是0a || b:a 是 truthy 就回傳 a,否則回傳 b。所以0 || 2是2,常用來設定預設值
falsy 是「放進 if 會被當成 false」的值,只有這幾個:false、0、-0、0n、''(空字串)、null、undefined、NaN。
其他的值都是 truthy,包括 '0'、'false'、[]、{}。!!x 可以把任何值轉成對應的布林值。
&& 與 || 的回傳值與短路
前三行對應投影片的邏輯運算子表。後半段的 sayHi 每被呼叫一次,就會印出一行字:第 11~13 行各寫了一次 sayHi(),播放時注意它實際被呼叫了幾次。
?? 與 ?.:處理「沒有值」
用 || 設定預設值有一個問題:0、'' 也是 falsy,會被當成「沒有值」而換成預設值。
ES2020 加入了兩個運算子,專門處理 null 和 undefined:
| 運算子 | 意思 | 例子 |
|---|---|---|
a ?? b |
空值合併:a 是 null 或 undefined 才用 b |
0 ?? 50 是 0(用 || 會得到 50) |
obj?.prop |
可選串連:obj 是 null 或 undefined 時直接得到 undefined,不會出錯 |
user.address?.city |
沒有 ?. 時,user.address.city 在 address 是 null 時會出現 TypeError: Cannot read properties of null。
條件(三元)運算子 條件 ? 值1 : 值2:條件成立得到值1,否則得到值2,適合「二選一」的簡短判斷。
?? 、?. 與三元運算子
settings.volume 是 0(使用者把音量調成靜音)。比較第 4、5 行:|| 和 ?? 誰尊重了這個 0?
運算子優先順序
一個運算式裡有好幾個運算子時,依優先順序計算(同一級通常由左到右)。由高到低大致是:
- 括號
( ) - 一元運算子:
!、typeof、++、--、正負號 - 次方
**(由右到左:2 ** 3 ** 2是2 ** 9) - 乘、除、餘數
*/% - 加、減
+- - 比較
<><=>=,再來是相等===!====!= &&,再來是||和??- 條件運算子
? : - 指定
=+=等
簡單記法:算術 > 比較 > 邏輯 > 條件 > 指定。&& 比 || 優先,所以 true || false && false 先算 false && false。
?? 不能直接和 &&、|| 混寫(例如 a || b ?? c 是語法錯誤),要加括號。
記不得的時候就加括號,程式也比較好讀。
位元運算子(&、|、^、~、<<、>>、>>>)把數字當成 32 位元的二進位來運算,例如 5 & 1 是 0101 & 0001,得到 1。
一般網頁程式很少用到,看到時知道它們是對位元運算即可。
優先順序:誰先算
每一行都先自己算一次再按下一步。第 9 行是投影片 Lab03 的題目;第 10 行看 && 比 || 優先;第 11 行的次方由右往左算。
想一想:邏輯運算子與優先順序
下面的程式會印出什麼?
console.log(0 || 'A', 0 ?? 'A');
下面的程式會印出什麼?
console.log('1' && 'str', 0 && 'str');
下面的程式會印出什麼?
const user = null;
console.log(user?.name ?? '訪客');
下面的程式會印出什麼?
console.log(1 + 2 * 3 ** 2);
實作:預設值與條件運算子
完成三個 TODO:沒有暱稱時顯示「同學」、0 分要保留為 0、用三元運算子判斷及格。完成後應該依序印出 同學、0、不及格。
重點精華回顧
- 運算式會算出一個值;運算子依運算元數量分成一元、二元、三元。
- 算術運算子
+ - * / % **;+遇到字串就變成連接,其他算術運算子會把字串轉成數字。x++先取值再加,++x先加再取值。 - 比較的結果是布林值;
==會先轉換型別,一律用===、!==。字串比較是逐字的字典順序。 &&、||會短路求值,回傳的是其中一個運算元;falsy 只有false、0、''、null、undefined、NaN(以及-0、0n)。??只在null、undefined時使用預設值,?.遇到null、undefined不會出錯;條件 ? 值1 : 值2做二選一。- 優先順序大致是 算術 > 比較 > 邏輯 > 條件 > 指定;不確定時加括號。