本文的目的是为了和大家分享如何从官方文档中获得答案  至于标题中和本文其他的语法也是非常不规范  在平时开发中需要极力避免使用`==`与不必要的类型转化

我先抛出一个例子 大部分人估计会很疑惑 在语言大战中 很多其他语言的人也经常抓住类似的例子来攻击js

但是js作为一个有规范的语言 所有的结果都要遵循规则吧 然后咱就来带大家看看 关于==语法在es 2017中的定义

为啥是2017呢 因为本文写的时候最新的标准就是这个版本 ECMAScript® 2017 Language Specification (ECMA-262, 8th edition, June 2017) 但是没有关系啊 我会截图给大家的

首先先看==的标准 Abstract Equality Comparison

提示一下 文中涉及到的类型 全都是指基本类型 js目前有七大基本类型: Undefined, Null, Boolean, String, Symbol, Number, Object. 为了和typeof返回值一致 我就都使用小写了

这个标准其实不复杂 其实也就十几个步骤 中间各种情况 咱画个流程图 文档中xy有先后顺序 咱们这就不管顺序了吧

中间就5个判断 总结一下 可以分为三组 进行区分

  1. 相同类型直接返回===结果
  2. object之间
    1. undefinednull遇见的时候为true
    2. string number boolean 两两遇见的时候将转化成number进行判断
    3. 其他情况返回false
  3. object与其他类型之间
    1. 遇到undefinednull, 返回false
    2. 遇到booleanboolean转化为number重新计算
    3. 其他情况获取object原始值进行重新计算

哎 这样就清晰了

啥是对象的原始值? 好了 这又得看另外一个规则了 toPrimitive

一个前置条件: 原始值不能为object

这个规则又是挺麻烦的一个 流程和情况分支也很多 我就总结一下这里用到的规则吧:

  1. 如果输入值具有名为Symbol.toPrimitive的函数, 函数运算结果即为原始值, 如果运算结果不合条件将会报错
  2. 计算valueOf方法的值, 运算结果如果符合条件则即为原始值
  3. 计算toString方法的值, 运算结果如果符合条件则即为原始值
  4. 如果以上没有获得原始值将报错

所以 这就是最终的答案

整个流程是这样的

1
2
3
4
5
6
![] == [] // 最初的等式
false == [] // !运算符对象直接转换成boolean
0 == [] // boolean转化为number
0 == "" // 对象转使用`toString`方法转化为原始值, 得到一个空字符串
0 == 0 // 空字符串转换数字0
true // 结果

而这个 ![] == ![]就比较简单 直接是类型强转false == falsetrue

[] == [] 也比较简单了 因为类型一样 所以返回[] === [] 而任何对象除了同一个引用之外不等于其他任何对象 所以答案是false

举一反三

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var dEmpty = {}
var dSymbol = { [Symbol.toPrimitive]: function() { return "" }}
var dValueOf = { valueOf: function() { return "" }}

dEmpty == !dEmpty
// => dEmpty == false // !运算符
// => dEmpty == 0 // boolean 转化为 0
// => "[object Object]" == 0 // 使用 toString 得到原始值
// => NaN == 0 // 转化为number NaN
// => false

dSymbol == !dSymbol
// => dSymbol == false
// => dSymbol == 0
// => "" == 0 // 使用 Symbol.toPrimitive 得到原始值""
// => 0 == 0

dValueOf == !dValueOf
// => dValueOf == false
// => dValueOf == 0
// => "" == 0 // 使用 valueOf 得到原始值""
// => 0 == 0