暗恋之纯粹,在于不求结果,彻底把本身锁闭在一个单向的关系里面。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)
最后,全部文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
做者:对角另外一面