這篇原本只想記下 NaN
、±0
、Object.is()
, 但 MDN 上已經有一篇相等比較的文章了,我就來整理一下 ES2015 官方文件裡面那些抽象的操作。內容基本上都在文件裡面的 7.2 這個章節中所提到的 13 個模式:
我大致上把這 13 種模式區分一下:
- 是否同類
- 是否相等
- 其他 此類待完善
內容的說明會依照程式的判斷順序下去講解,如下:
- 第一步
- 第二步
- 第三步
- 諸如此類……
當然內容以我根據官方規範所理解的來講,內容可能還是會有所紕漏。待以後瞭解詳細的細節會再完善,也歡迎讀者提供資訊以及文中的錯誤。
是否同類
isArray()
一般實作為 Array.isArray()
來調用。
- 如果型別不屬於物件型別,像是:Undefinied、Null、布林、字串、數字等基型值 (Primitive Value),包括了新的
Symbol
,直接回傳false
。 - 如果是一個陣列物件 (Array Exotic Objects),則回傳
true
。
這個部分比較難懂,大致上可以理解為我們平常所使用到的陣列,但不包含類陣列 (Array-like) 的型式。 - 如果是一個代理物件 (Proxy Exotic Objects),則會:
- 檢查代理處理器 (Proxy Handler) 是否為
null
,若為null
則拋出TypeError
錯誤。 - 將代理目標 (Proxy Target) 作為引數傳入
isArray()
中再進行判斷。
- 檢查代理處理器 (Proxy Handler) 是否為
- 其他則回傳
false
。
MDN 上的實作參考如下:
if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; }
isInteger()
一般實作為 Number.isInteger()
來調用。
- 如果型別不屬於數字型別,直接回傳
false
。 - 如果是
NaN
、Infinity
或-Infinity
,則回傳false
。 - 如果傳入的引數 (argument) 的絕對值不等於本身絕對值下取整後的結果,則回傳
false
。
下取整意為尋找一個不超過其本身的整數中裡面最大的那一個整數,簡單的例子:傳入5.5
後,下取整就是找比 5.5 還要小的整數們,像是:0、1、2、3、4、5 這些,接著找這些整數中最大的那一個!也就是 5,這也就是說「5 就是 5.5 的下取整結果」。
要特別注意浮點數中的精度,像是1.0000000000000001
這樣的例子。 - 其他則回傳
true
。
MDN 上的實作參考如下:
Number.isInteger = Number.isInteger || function(value) { return typeof value === 'number' && isFinite(value) && Math.floor(value) === value; };
IsRegExp()
這個方法沒看到瀏覽器實作,但 underscore.js 與 lodash 中有相關的函式可以使用。但好像沒有依照 ECMA 的標準下去執行,另外瀏覽器對於 RegExp 的支援度好像也各有不同。
- 如果型別不屬於物件型別,直接回傳
false
。 - Let isRegExp be Get(argument, @@match). 這個不太會解釋
- 非衝突則繼續,否則 return。
- 如果
IsRegExp()
不是undefinied
,則回傳IsRegExp()
的布林化結果。 - 如果有 RegExpMatcher 的物件內部 slot,則回傳
true
。 - 其他則回傳
false
。
是否相等*
SameValue()
同值相等,一般實作在 Object.is()
的比較方法上。
- 檢查傳入引數,兩者皆非衝突則繼續,否則 return。
- 如果左邊型別與右邊型別不同,則回傳
false
。 - 如果左邊是
undefinied
,則回傳true
。 - 如果左邊是
null
,則回傳true
。 - 如果左邊是數字型別:
- 若兩者皆為
NaN
,則回傳true
。 - 若左邊是
+0
而右邊是-0
,則回傳false
。 - 若左邊是
-0
而右邊是+0
,則回傳false
。 - 若左邊的數值與右邊的數值相等,則回傳
true
。 - 其他則回傳
false
。
- 若兩者皆為
- 如果左邊是字串型別:
- 兩者具有相同的字串長度與相對應的程式碼序列時回傳
true
。 - 其他則回傳
false
。
- 兩者具有相同的字串長度與相對應的程式碼序列時回傳
- 如果左邊是布林型別:
- 兩者皆為
true
或皆為false
,則回傳true
。 - 其他則回傳
false
。
- 兩者皆為
- 如果左邊是 Symbol 型別:
- 兩者具有相同的 Symbol 值時回傳
true
。 - 其他則回傳
false
。
- 兩者具有相同的 Symbol 值時回傳
- 如果兩者為相同的物件時回傳
true
,其他則回傳false
。
相同意指在兩者皆指向 (refer to) 同一個底層物件,當作是同樣的物件參照 (by same reference) 應該比較好理解。
SameValueZero()
零值相等,一般實作在 Map 物件中判斷「鍵的相等性」。
- 檢查傳入引數,兩者皆非衝突則繼續,否則 return。
- 如果左邊型別與右邊型別不同,則回傳
false
。 - 如果左邊是
undefinied
,則回傳true
。 - 如果左邊是
null
,則回傳true
。 - 如果左邊是數字型別:
- 若兩者皆為
NaN
,則回傳true
。 - 若左邊是
+0
而右邊是-0
,則回傳true
。 - 若左邊是
-0
而右邊是+0
,則回傳true
。 - 若左邊的數值與右邊的數值相等,則回傳
true
。 - 其他則回傳
false
。
- 若兩者皆為
- 如果左邊是字串型別:
- 兩者具有相同的字串長度與相對應的程式碼序列時回傳
true
。 - 其他則回傳
false
。
- 兩者具有相同的字串長度與相對應的程式碼序列時回傳
- 如果左邊是布林型別:
- 兩者皆為
true
或皆為false
,則回傳true
。 - 其他則回傳
false
。
- 兩者皆為
- 如果左邊是 Symbol 型別:
- 兩者具有相同的 Symbol 值時回傳
true
。 - 其他則回傳
false
。
- 兩者具有相同的 Symbol 值時回傳
- 如果兩者為相同的物件時回傳
true
,其他則回傳false
。
相同意指在兩者皆指向 (refer to) 同一個底層物件,當作是同樣的物件參照 (by same reference) 應該比較好理解。
注:與同值相等差別在 +0 與 −0 的判斷。
===
嚴格相等,就是在 JavaScript 中常使用的三等號。
- 檢查傳入引數,兩者皆非衝突則繼續,否則 return。
- 如果左邊型別與右邊型別不同,則回傳
false
。 - 如果左邊是
undefinied
,則回傳true
。 - 如果左邊是
null
,則回傳true
。 - 如果左邊是數字型別:
- 若兩者皆為
NaN
,則回傳false
。 - 若左邊是
+0
而右邊是-0
,則回傳true
。 - 若左邊是
-0
而右邊是+0
,則回傳true
。 - 若左邊的數值與右邊的數值相等,則回傳
true
。 - 其他則回傳
false
。
- 若兩者皆為
- 如果左邊是字串型別:
- 兩者具有相同的字串長度與相對應的程式碼序列時回傳
true
。 - 其他則回傳
false
。
- 兩者具有相同的字串長度與相對應的程式碼序列時回傳
- 如果左邊是布林型別:
- 兩者皆為
true
或皆為false
,則回傳true
。 - 其他則回傳
false
。
- 兩者皆為
- 如果左邊是 Symbol 型別:
- 兩者具有相同的 Symbol 值時回傳
true
。 - 其他則回傳
false
。
- 兩者具有相同的 Symbol 值時回傳
- 如果兩者為相同的物件時回傳
true
,其他則回傳false
。
相同意指在兩者皆指向 (refer to) 同一個底層物件,當作是同樣的物件參照 (by same reference) 應該比較好理解。
注:與同值相等差別在 ±0 與 NaN 的判斷。
==
一般相等,或是文件上所說的抽象相等,也是我們在 JavaScript 中常使用的雙等號。
- 檢查傳入引數,兩者皆非衝突則繼續,否則 return。
- 若兩者皆是同樣型別,則調用
===
嚴格相等比較。 - 如果左邊是
null
而右邊是undefinied
,則回傳true
。 - 如果左邊是
undefinied
而右邊是null
,則回傳true
。 - 如果左邊是數字型別而右邊是字串型別,將右邊轉為數字型別再進行
==
一般相等比較。 - 如果左邊是字串型別而右邊是數字型別,將右邊轉為字串型別再進行
==
一般相等比較。 - 如果左邊是布林型別,將左邊轉為數字型別再進行
==
一般相等比較。 - 如果右邊是布林型別,將右邊轉為數字型別再進行
==
一般相等比較。 - 如果左邊是字串或數字或 Symbol 且右邊是物件,將右邊轉為基型值後再進行
==
一般相等比較。 - 如果左邊是物件且右邊是字串或數字或 Symbol,將左邊轉為基型值後再進行
==
一般相等比較。 - 其他則回傳
false
。
物件轉型可參考 JavaScript 型別轉換的那些事
對照
同值相等、零值相等和嚴格相等的差異對照
SameValue(x,y) | SameValueZero(x,y) | x===y | |
---|---|---|---|
NaN | true |
true |
true |
±0 | false |
true |
false |
四種相等的比較
參考 MDN 範例
其他
關係比較 x < y
雖然比較運算對各種型別的運算元來說都可以進行估算,但關係比較實際上只會對數字與字串這兩種基型值進行估算。估算時還會因為 JavaScript 中所指定的自左至右的表達式估算順序以及 ECMAScript 規範中所提到的 LeftFirst 影響,但這個部分我看了也不是很懂就先參考 JavaScript 大全 /6e 中的結合 ECMA-262 規範整理規則。
- 檢查傳入引數,兩者皆非衝突則繼續,否則 return。
- 如果有任一引數為物件型別,則將其轉為基型值再進行比較。
- 會先將轉換後的值作為 px 以及 py 來繼續執行估算。
- 如果 px 以及 py 兩者轉換後皆為字串型別,則會依照字母順序的比較:
- 若 py 這個字串是 px 的前綴 (即使 字串 px 是 py 加上一個空字串) 則回傳
false
。 - 若 px 這個字串是 py 的前綴則回傳
true
。 - 找出兩者中最先出現不同的字元程式碼 (一般為 16 位元的 Unicode,UTF-16) 序列點的值作為 m 與 n,若 m<n 則回傳
true
,否則回傳false
。
- 若 py 這個字串是 px 的前綴 (即使 字串 px 是 py 加上一個空字串) 則回傳
- 如果 px 以及 py 兩者轉換後有任一個不是字串型別,則將 px 以及 py 兩者轉換為數字型別的 nx 以及 ny 來繼續執行估算,兩者皆非衝突則繼續,否則 return。
- 如果 nx 是
NaN
,則回傳undefined
。 - 如果 ny 是
NaN
,則回傳undefined
。 - 如果兩者是相同的數值則回傳
false
。 - 如果 nx 是
+0
且 ny 是-0
,則回傳false
。 - 如果 nx 是
-0
且 ny 是+0
,則回傳false
。 - 如果 nx 是
Infinity
,則回傳false
。 - 如果 ny 是
Infinity
,則回傳true
。 - 如果 ny 是
-Infinity
,則回傳false
。 - 如果 nx 是
-Infinity
,則回傳false
。 - 如果 nx 在數學上的數值比 ny 在數學上的數值來的小,則回傳
true
,否則回傳false
。
物件轉型可參考 JavaScript 型別轉換的那些事
數學上的數值已經限定在兩者皆有限以及兩者皆非零的集合
在小於等於<=
的關係判斷中所代表的是不大於的判斷,也就是回傳!(x > y)
,反之亦然
以下待補
物件強制轉型 RequireObjectCoercible()
是否能被呼叫 IsCallable()
判斷該引數是否為一個具備外部間接調用的方法的函式。
是否為建構式 IsConstructor()
判斷該引數是否為一個具備建構函式的函式物件 (function object)。
是否能夠擴充 IsExtensible()
判斷該引數是否能在該物件上加入新的特性。
是否能作為特性 IsPropertyKey()
判斷該引數是否能在物件中作為一個特性。