资讯专栏INFORMATION COLUMN

JavaScript "相等" 的二三事

wanghui / 2433人阅读

摘要:还规定了无穷及其它的相应规范,有兴趣可自行查找相关资料。其它相同数值相等。类型中,引用同一对象,相等。不同点对的判断上各有不同。以为代表的相等和相等以为代表的不相等和相等以为代表的相等和不相等相同类型采用严格比较。

相等不相等?

先来随便举几个?吧~

"0" == true          //?
[1] == [1]           //?
[1] == 1             //?
null == false        //?
null == undefined    //?
NaN === NaN          //?
+0 === -0            //?
Object.is([], [])    //?
Object.is(-0, +0)    //?
Object.is(NaN, NaN)  //?

var arr = [NaN, 0, +0]
arr.indexOf(-0)      //?
arr.indexOf(NaN)     //?
arr.includes(-0)     //?
arr.includes(NaN)    //?

可能 ±0NaN 会纠结一点,还是比较基础的,也许很多人一眼扫过去便知道答案了,网上也已经有了很多相关的经验总结。我在这里结合官方规范进行了整理,希望能带给你不一样的认识。

预备知识 ECMAScript Language Types

传送门。根据最新规范,EcmaScript 一共有7种语言类型:

Undefined

Null

Number

String

Boolean

Symbol

Object

我们经常把 Object 类型称为 引用数据类型其它5种则为基本数据类型。(Symbol怎么说..?

ToNumber

传送门。任意 EcmaScript 类型转化为 Number 类型

类型 结果
Undefined NaN
Null +0
Boolean true -> 1,false -> +0
Number 不转变
String 空字符串 -> +0,有效的数字 -> 十进制数字,其它 -> NaN
Object 先ToPrimitive(hint Number),再ToNumber
Symbol 抛错,TypeError 错误
ToPrimitive

传送门。内部方法,主要功能是将引用数据类型转化为基本数据类型

根据内部标记 hint 的不同有不同的调用顺序。

hint有三种:defaultnumberstringdefault 默认遵照 number 规则。

default/number:先 valueOf,后 toString。一般转化规则皆如此。

string:先 toString,后 valueOf。如Date对象方法、String()转化等。

如果 toString/valueOf 中某一方法返回类型不为对象类型,则直接返回该值,不会继续调用后面方法。如果两者都返回对象类型,会抛 TypeError 错误。

-0、+0、0 的疑惑

明明日常没什么卵用,为什么会有±0?

其实遵从IEEE754标准的编程语言都有±0的概念,IEEE754标准的64位浮点数,是以1+11+53形式的符号位+阶数位+尾数位表示。

符号位、阶数位、尾数位都是0,那便是+0,也就是常规的数字0

符号位为1,阶数位、尾数位都是0,那便是 -0

IEEE754还规定了NaN无穷及其它的相应规范,有兴趣可自行查找相关资料。

PS

这部分其实是后加的,你会发现每个知识点都是紧密相连的,构成了一个庞大的知识网络,限于篇幅我不会详细介绍,但我会尽量贴出规范出处,大家可自行研究。

SameValueNonNumber 内部方法

SameValueNonNumber 方法接收两个参数 x 和 y ,其中 x 和 y 都不是 Number 类型,该方法返回 truefalse

主要规则

断言:x 不是 Number 类型。

断言:x 和 y 是 相同类型。

如果 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

小结

相同类型比较规则(除Number类型)

都是 undefined,相等

都是 null,相等

String 类型中,都是相同字符串,相等

Boolean 类型中,都是 true 或者 都是 false,相等

Symbol 类型中,都是相同 Symbol 值,相等

Object 类型中,引用同一对象,相等

使用

哪些 JavaScript 公开方法采用了 SameValueNonNumber 比较呢?

公开方法木有

接着看下去你就会知道,撇开数值类型比较,SameValueNonNumberSameValueSameValueZero=== 的公共方法。

SameValueZero 内部方法

SameValueZero 方法接收两个参数 x 和 y ,其中 x 和 y 是 EcmaScript 任意类型值,该方法返回 truefalse

主要规则

如果 x 和 y 的类型不同,返回 false

如果 x 是 Number 类型:

如果 x 和 y 都是 NaN ,返回 true

如果 x 是 -0 ,y 是 +0 ,返回 true

如果 x 是 +0 ,y 是 -0 ,返回 true

如果 x 和 y 数值相等,返回 true

返回 false

返回 SameValueNonNumber(x, y) 方法的返回值。

小结

不同类型不相等

Number 类型中:±0 相等。NaN 和 NaN 相等。其它相同数值相等

SameValueNonNumber 比较:

都是 undefined,相等

都是 null,相等

String 类型中,都是相同字符串,相等

Boolean 类型中,都是 true 或者 都是 false,相等

Symbol 类型中,都是相同 Symbol 值,相等

Object 类型中,引用同一对象,相等

使用

哪些 JavaScript 公开方法采用了 SameValueZero 比较呢?

Array.prototype.includes

Map.prototype.delete

Map.prototype.has

Map.prototype.set

Set.prototype.delete

Set.prototype.has

Set.prototype.add

ArrayBuffer 和 DataView 部分方法

SameValue 内部方法

SameValue 方法接收两个参数 x 和 y ,其中 x 和 y 是 EcmaScript 中任意类型值,该方法返回 truefalse

主要规则

如果 x 和 y 的类型不同,返回 false

如果 x 是 Number 类型:

如果 x 和 y 都是 NaN ,返回 true

如果 x 是 -0 ,y 是 +0 ,返回 false

如果 x 是 +0 ,y 是 -0 ,返回 false

如果 x 和 y 数值相等,返回 true

返回 false

返回 SameValueNonNumber(x, y) 方法的返回值。

小结

不同类型不相等

Number 类型中:±0 不相等。NaN 和 NaN 相等。其它相同数值相等

SameValueNonNumber 比较:

都是 undefined,相等

都是 null,相等

String 类型中,都是相同字符串,相等

Boolean 类型中,都是 true 或者 都是 false,相等

Symbol 类型中,都是相同 Symbol 值,相等

Object 类型中,引用同一对象,相等

使用

哪些 JavaScript 公开方法采用了 SameValue 比较呢?

Object.is

在最新的 ES 规范 中,你会发现许多其它内部方法和公开方法都应用了 SameValue 比较方法,其中大部分也没有涉及数值比较。

至于为什么是 SameValue 方法,而不是 SameValueZero===。其实我也不知道。。。我个人倾向于认为:SameValue 方法原本在 ES5 规范中便存在了,最新的规范是为了保持规范一致而继续沿用。

=== 严格相等运算

Strict Equality Comparison,x === y,返回 true 或者 false

主要规则

如果 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

返回 SameValueNonNumber(x, y) 方法的返回值。

小结

不同类型不相等

Number 类型中:±0 相等。NaN 和 NaN 不相等。其它相同数值相等

SameValueNonNumber比较:

都是 undefined,相等

都是 null,相等

String 类型中,都是相同字符串,相等

Boolean 类型中,都是 true 或者 都是 false,相等

Symbol 类型中,都是相同 Symbol 值,相等

Object 类型中,引用同一对象,相等

使用

哪些 JavaScript 公开方法采用了 === 比较呢?

=== 严格相等运算

左右两边是相同类型的 == 相等运算

switch语句中的case

Array.prototype.indexOf

Array.prototype.lastIndexOf

== 相等运算

Abstract Equality Comparison,x == y,返回 true 或者 false

主要规则

如果 x 和 y 的类型相同:

返回严格相等运算结果 x === y 。

如果 x 是 null ,y 是 undefined ,返回 true

如果 x 是 undefined ,y 是 null ,返回 true

如果 x 是 Number 类型 ,y 是 String 类型,返回 x == ToNumber(y) 运算结果。

如果 x 是 String 类型 ,y 是 Number 类型,返回 ToNumber(x) == y 运算结果。

如果 x 是 Boolean 类型 ,返回 ToNumber(x) == y 运算结果。

如果 y 是 Boolean 类型 ,返回 x == ToNumber(y) 运算结果。

如果 x 是 Number、String、Symbol 中任意一个类型 ,y 是 Object 类型,返回 x == ToPrimitive(y) 运算结果。

如果 y 是 Number、String、Symbol 中任意一个类型 ,x 是 Object 类型,返回 ToPrimitive(x) == y 运算结果。

返回 false

小结

相同类型:遵循 === 严格相等比较规则。

null == undefined,相等

不同类型:

基本数据类型转换为 Number 类型再 == 比较。

引用数据类型执行内部 ToPrimitive方法后再 == 比较。

使用

哪些 JavaScript 公开方法采用了 == 比较呢?

只有这只 == 相等运算

相等不相等

开头的答案。如果对结果感到好奇,不妨对着上面的过程比对~

"0" == true         // false
[1] == [1]          // false
[1] == 1            // true
null == false       // false
null == undefined   // true
NaN === NaN         // false
+0 === -0           // true
Object.is([], [])   // false
Object.is(-0, +0)   // false。见SameValue
Object.is(NaN, NaN) // true。见SameValue

var arr = [NaN, 0, +0]
arr.indexOf(-0)     // 1。见===
arr.indexOf(NaN)    // -1。见===
arr.includes(-0)    // true。见SameValueZero
arr.includes(NaN)   // true。见SameValueZero
总结

SameValueZeroSameValue===这仨完全差不多嘛!

相同点:

- 不同类型即不相等。
- 相同类型遵从`SameValueNonNumber`规则。

不同点:对±0NaN 的判断上各有不同。

Array.prototype.includes 为代表的SameValueZero

±0 相等

NaN 和 NaN 相等

Object.is 为代表的SameValue

±0 不相等

NaN 和 NaN 相等

===Array.prototype.indexOf 为代表的===

±0 相等

NaN 和 NaN 不相等

==

相同类型采用===严格比较。

不同类型会隐式转换:

基本数据类型转换为 Number 类型再 == 比较。

引用数据类型执行 ToPrimitive 转换后再 == 比较。

undefined/null 特例。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92237.html

相关文章

  • 数组方法的二三事

    摘要:常用的数组方法删除数组的最后一个元素,返回被删除的元素,原数组长度减。原数组发生了变化,但没有创建新的数组。将指定数组进行排序,返回排好序的数组。颠倒数组元素的顺序,返回逆序后的数组。 数组,对于每一个前端人员来说是非常常见且重要的数据结构之一,也是面试常常出现的题目,掌握数组的方法能帮助我们更高效地处理问题。不过在数组的学习中,我们常常会混淆数组本身的方法和Javascript提供的...

    VincentFF 评论0 收藏0
  • 前端渲染过程的二三事

    摘要:前端渲染过程的二三事本文不会介绍整个前端渲染过程的步骤,只是记录最近阅读的文章的些许思考和感悟。那么现在我们可以明白这个问题的关键所在了,因为在大部分页面中是拥有的,而由于其解析顺序,那么在事件之前必定已经成功构造树。 前端渲染过程的二三事 本文不会介绍整个前端渲染过程的步骤,只是记录最近阅读的文章的些许思考和感悟。(文章地址一(系列),文章地址二) 希望大家在阅读这篇文章之前能将上述...

    Rindia 评论0 收藏0
  • 与dom事件流相关的二三事

    摘要:但对于整个事件流上的别的元素来说,执行顺序还会受到另外一个因素的影响。以上面的场景为例,在捕获阶段执行的事件,如果执行,则事件流终止,不会到达目标阶段,的世界则不会被执行执行结果为线上参考事件流 向dom绑定事件的事件的三种方式 行内绑定 按钮 js内绑定 btnDom.onclick = function clickHandler() { console.log(click)...

    Anleb 评论0 收藏0
  • 分表后需要注意的二三事

    摘要:分表字段的选择。问题产生之前提到在分表应用上线前我们需要将原有表的数据迁移到新表中,这样才能保证业务不受影响。虽说凌晨的业务量下降,但依然有少部分的请求过来,也会出现各种数据库异常。 showImg(https://segmentfault.com/img/remote/1460000019462791?w=496&h=285); 前言 本篇是上一篇《一次分表踩坑实践的探讨》,所以还没...

    dongxiawu 评论0 收藏0

发表评论

0条评论

wanghui

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<