暗戀之純粹,在於不求結果,徹底把本身鎖閉在一個單向的關係裏面。javascript
——梁文道《暗戀到偷窺》java
本文爲讀 lodash 源碼的第五篇,後續文章會更新到這個倉庫中,歡迎 star:pocket-lodashgit
gitbook也會同步倉庫的更新,gitbook地址:pocket-lodashes6
本篇分析的是 eq
函數。github
eq
函數用來比較兩個值是否相等。遵循的是 SameValueZero 規範。安全
var obj1 = {test: 1} var obj2 = {test: 1} var obj3 = obj1 _.eq(1,1) // true _.eq(+0, -0) // true _.eq(obj1, obj3) // true _.eq(obj1, obj2) // false _.eq(NaN, NaN) // false
這個規範規定比較的值 x
和 y
都不爲 Number
類型,照抄規範以下:微信
x
的類型不爲 Number
類型y
的類型與 x
的類型一致x
的類型爲 Undefined
,返回 true
x
的類型爲 Null
,返回 true
x
的類型爲 String
,而且 x
和 y
的長度及編碼相同,返回 true
,不然返回 false
x
的類型爲 Boolean
,而且 x
和 y
同爲 true
或同爲false
,返回 true
,不然返回 false
x
的類型爲 Symbol
,而且 x
和 y
具備相同的 Symbol
值,返回 true
,不然返回 false
x
和 y
指向同一個對象,返回 true
, 不然返回 false
js 中的全等(===
)即是遵循這個規範,照搬規範以下:函數
x
和 y
的類型不一樣,返回 false
x
的爲 Number
類型:
x
爲 NaN
,返回 false
y
爲 NaN
,返回 false
x
和 y
的數值一致,返回 true
x
爲 +0
而且 y
爲 -0
,返回 true
x
爲 -0
而且 y
爲 +0
,返回 true
false
規範以下:源碼分析
x
和 y
的類型不一樣,返回 false
x
的類型爲 Number
x
爲 NaN
而且 y
爲 NaN
,返回 true
x
爲 +0
而且 y
爲 -0
,返回 false
x
爲 -0
而且 y
爲 +0
, 返回 false
x
和 y
的數值一致,返回 true
false
這個是 eq
遵循的規範,以下:編碼
x
和 y
的類型不一樣,返回 false
x
的類型爲 Number
x
爲 NaN
而且 y
爲 NaN
,返回 true
x
爲 +0
而且 y
爲 -0
,返回 true
x
爲 -0
而且 y
爲 +0
, 返回 true
x
和 y
的數值一致,返回 true
false
小結:SameValueNonNumber
是基本,Strict Equality Comparison
、SameValue
和 SameValueZero
只是在對待 +0
、-0
和 NaN
上有區別。
來看下 eq
的源碼:
function eq(value, other) { return value === other || (value !== value && other !== other) }
其實eq
的源碼其實就只有這麼一句。
既然 eq
遵循的是 SameValueZero
規範,那就將源碼來拆解一下,看它是怎樣符合規範的。
首先,看第一部分:
value === other
就是這麼一段,符合的是 Strict Equality Comparison
規範,經過對比能夠發現, Strict Equality Comparison
和 SameValueZero
只在對待 NaN
上有區別。
Strict Equality Comparison
規定就算 x
和 y
都爲 NaN
時,返回的是 false
, NaN === NaN
返回的就是 false
。可是 SameValueZero
返回的是規定 x
和 y
都爲 NaN
時返回的是 true
。所以只須要在 Strict Equality Comparison
的基礎上處理 NaN
就能夠了。
下面這段即是處理 NaN
的:
(value !== value && other !== other)
在 js 中,只有 NaN
和自身是不相等的,當兩個須要比較的值都是和自身不相等時,代表這兩個值都爲 NaN
,返回 true
。
這樣便遵循了 SameValueZero
的比較實現。
Object.is(NaN, NaN)
返回的是 true
,因此 eq
一樣能夠改爲:
function eq(value, other) { return value === other || Object.is(value, other) }
Object.is
一樣是比較兩個值是否同樣,可是 Object.is(+0, -0)
返回的是 false
, 它遵循是的 SameValue
規範,所以不能夠直接用 Object.is
替代 eq
。
還有個 isNaN
的全局方法,能夠用來判斷一個值是否爲 NaN
。例如 isNaN(NaN)
會返回 true
,那 eq
是否能夠改爲如下形式呢?
function eq(value, other) { return value === other || (isNaN(value) && isNaN(other)) }
答案是:不能夠!
isNaN
有一個很怪異的行爲,若是傳入的參數不爲 Number
類型,會嘗試轉換成 Number
類型以後再作是否爲 NaN
的判斷。因此相似 isNaN('notNaN')
返回的也是 true
,由於字符串 notNaN
會先被轉換成 NaN
再作判斷,這不是咱們想要的結果。
爲了修復 isNaN
的缺陷,es6
在 Number
對象上擴展了 isNaN
方法,只有是 NaN
時纔會返回 true
,所以用 Number.isNaN
來判斷是安全的。因此 eq
一樣能夠改爲如下形式:
function eq(value, other) { return value === other || (Number.isNaN(value) && Number.isNaN(other)) }
署名-非商業性使用-禁止演繹 4.0 國際 (CC BY-NC-ND 4.0)
最後,全部文章都會同步發送到微信公衆號上,歡迎關注,歡迎提意見:
做者:對角另外一面