JavaScript for impatient programmers (ES2022 版)
請支持這本書:購買捐款
(廣告,請不要封鎖。)

13 運算子



13.1 理解運算子

JavaScript 的運算子可能看起來很奇怪。有了以下兩個規則,它們就更容易理解

13.1.1 運算子會強制轉換其運算元為適當的類型

如果運算子取得的運算元類型不正確,它很少會引發例外。相反,它會強制轉換(自動轉換)運算元,以便它可以處理它們。我們來看兩個例子。

首先,乘法運算子只能處理數字。因此,它會在計算結果之前將字串轉換為數字。

> '7' * '3'
21

其次,用於存取物件屬性的方括號運算子 ([ ]) 只能處理字串和符號。所有其他值都會強制轉換為字串

const obj = {};
obj['true'] = 123;

// Coerce true to the string 'true'
assert.equal(obj[true], 123);

13.1.2 大多數運算子僅適用於原始值

如前所述,大多數運算子僅適用於原始值。如果運算元是物件,它通常會強制轉換為原始值,例如

> [1,2,3] + [4,5,6]
'1,2,34,5,6'

為什麼?加號運算子會先強制轉換其運算元為原始值

> String([1,2,3])
'1,2,3'
> String([4,5,6])
'4,5,6'

接下來,它會串接兩個字串

> '1,2,3' + '4,5,6'
'1,2,34,5,6'

13.2 加號運算子 (+)

加號運算子在 JavaScript 中的工作方式如下

字串模式讓我們可以使用 + 來組合字串

> 'There are ' + 3 + ' items'
'There are 3 items'

數字模式表示如果兩個運算元都不是字串(或會變成字串的物件),則所有內容都會強制轉換為數字

> 4 + true
5

Number(true)1

13.3 指定運算子

13.3.1 一般指定運算子

一般指定運算子用於變更儲存位置

x = value; // assign to a previously declared variable
obj.propKey = value; // assign to a property
arr[index] = value; // assign to an Array element

變數宣告中的初始化值也可以視為指定的一種形式

const x = value;
let y = value;

13.3.2 複合指定運算子

JavaScript 支援下列指定運算子

13.3.2.1 邏輯指定運算子 [ES2021]

邏輯指定運算子的運作方式與其他複合指定運算子不同

指定運算子 等同於 僅在 a
a ||= b a || (a = b) 假值
a &&= b a && (a = b) 真值
a ??= b a ?? (a = b) 空值

為什麼 a ||= b 等同於下列表達式?

a || (a = b)

為什麼不等於這個表達式?

a = a || b

前一個表達式有 短路運算 的好處:只有在 a 評估為 false 時才會評估指定。因此,只有在必要時才會執行指定。相反地,後一個表達式總是會執行指定。

有關 ??= 的更多資訊,請參閱 §14.4.5「空值合併指定運算子 (??=) [ES2021]」

13.3.2.2 其餘的複合指定運算子

對於 || && ?? 以外的運算子 op,下列兩種指定方式是等同的

myvar op= value
myvar = myvar op value

例如,如果 op+,則我們會得到運算子 +=,其運作方式如下。

let str = '';
str += '<b>';
str += 'Hello!';
str += '</b>';

assert.equal(str, '<b>Hello!</b>');

13.4 相等性:=====

JavaScript 有兩種相等性運算子:寬鬆相等性 (==) 和嚴格相等性 (===)。建議總是使用後者。

  ===== 的其他名稱

13.4.1 寬鬆相等(==!=

寬鬆相等是 JavaScript 的怪癖之一。它經常強制轉換運算元。其中一些強制轉換是有意義的

> '123' == 123
true
> false == 0
true

其他則不然

> '' == 0
true

如果(且僅當!)另一個運算元為原始值時,物件會強制轉換為原始值

> [1, 2, 3] == '1,2,3'
true
> ['1', '2', '3'] == '1,2,3'
true

如果兩個運算元都是物件,則只有它們是同一個物件時才相等

> [1, 2, 3] == ['1', '2', '3']
false
> [1, 2, 3] == [1, 2, 3]
false

> const arr = [1, 2, 3];
> arr == arr
true

最後,== 認為 undefinednull 相等

> undefined == null
true

13.4.2 嚴格相等(===!==

嚴格相等從不強制轉換。只有當兩個值具有相同的類型時,它們才相等。讓我們重新檢視我們先前與 == 運算元的互動,看看 === 運算元做了什麼

> false === 0
false
> '123' === 123
false

物件僅當另一個值是同一個物件時才相等

> [1, 2, 3] === '1,2,3'
false
> ['1', '2', '3'] === '1,2,3'
false

> [1, 2, 3] === ['1', '2', '3']
false
> [1, 2, 3] === [1, 2, 3]
false

> const arr = [1, 2, 3];
> arr === arr
true

=== 運算元不認為 undefinednull 相等

> undefined === null
false

13.4.3 建議:始終使用嚴格相等

我建議始終使用 ===。它使您的程式碼更容易理解,並讓您不必考慮 == 的怪癖。

讓我們看看 == 的兩個使用案例,以及我建議的替代方案。

13.4.3.1 == 的使用案例:與數字或字串比較

== 讓您可以檢查值 x 是否為數字或該數字作為字串,只需進行一次比較

if (x == 123) {
  // x is either 123 or '123'
}

我比較喜歡以下兩個替代方案

if (x === 123 || x === '123') ···
if (Number(x) === 123) ···

您也可以在第一次遇到 x 時將其轉換為數字。

13.4.3.2 == 的使用案例:與 undefinednull 比較

== 的另一個使用案例是檢查值 x 是否為 undefinednull

if (x == null) {
  // x is either null or undefined
}

此程式碼的問題在於您無法確定某人是否打算這樣寫,或者他們是否打錯字,而意思是 === null

我比較喜歡以下兩個替代方案

if (x === undefined || x === null) ···
if (!x) ···

第二種替代方案的缺點是它接受除了 undefinednull 以外的值,但這是 JavaScript 中一個根深蒂固的模式(將在 §15.3「基於真值性的存在檢查」 中詳細說明)。

以下三個條件也大致相等

if (x != null) ···
if (x !== undefined && x !== null) ···
if (x) ···

13.4.4 比 === 更嚴格:Object.is()

方法 Object.is() 比較兩個值

> Object.is(123, 123)
true
> Object.is(123, '123')
false

它比 === 更嚴格。例如,它將 NaN(涉及數字運算的錯誤值)視為等於它自己

> Object.is(NaN, NaN)
true
> NaN === NaN
false

這偶爾會很有用。例如,您可以使用它來實作陣列方法 .indexOf() 的進階版本

const myIndexOf = (arr, elem) => {
  return arr.findIndex(x => Object.is(x, elem));
};

myIndexOf() 會在陣列中找到 NaN,而 .indexOf() 則不會

> myIndexOf([0,NaN,2], NaN)
1
> [0,NaN,2].indexOf(NaN)
-1

結果 -1 表示 .indexOf() 無法在陣列中找到其引數。

13.5 排序運算子

表 3:JavaScript 的排序運算子。
運算子 名稱
< 小於
<= 小於或等於
> 大於
>= 大於或等於

JavaScript 的排序運算子(表 3)適用於數字和字串

> 5 >= 2
true
> 'bar' < 'foo'
true

<=>= 基於嚴格相等性。

  排序運算子不適用於人類語言

排序運算子不適用於比較人類語言中的文字,例如,涉及大小寫或重音時。詳情說明於 §20.6「比較字串」

13.6 其他各種運算子

以下運算子在本指南的其他章節中涵蓋

接下來的兩個小節討論兩個很少使用的運算子。

13.6.1 逗號運算子

逗號運算子有兩個運算元,會評估它們並傳回第二個運算元

> 'a', 'b'
'b'

有關此運算子的更多資訊,請參閱 Speaking JavaScript

13.6.2 void 運算子

void 運算子會評估其運算元並傳回 undefined

> void (3 + 2)
undefined

有關此運算子的更多資訊,請參閱 Speaking JavaScript

  測驗

請參閱 測驗應用程式