ECMAScript 5.1 规范 之 ==

96 阅读3分钟

很久之前看到了一个问题,解释为什么 console.log( [] == ![]) 会输出 true,于是乎,开始看 ECMAScript 5.1 规范。(6.0的后面补充)

前言 Types

在本规范中,符号“Type(x)”用作“x 的类型”的简写,其中“type”指的是本节中定义的 ECMAScript 语言和规范类型。

本规范中的算法操作每个值都有关联的类型。 可能的值类型正是本子句中定义的值类型。 类型进一步细分为 ECMAScript 语言类型和规范类型。

ECMAScript 语言类型对应于 ECMAScript 程序员使用 ECMAScript 语言直接操作的值。 ECMAScript 语言类型包括 Undefined, Null, Boolean, String, Number, and Object

规范类型对应于算法中使用的元值,用于描述 ECMAScript 语言构造和 ECMAScript 语言类型的语义。 规范类型包括引用、列表、完成、属性描述符、属性标识符、词法环境和环境记录。 规范类型值是规范工件,不一定对应于 ECMAScript 实现中的任何特定实体。 规范类型值可用于描述 ECMAScript 表达式求值的中间结果,但此类值不能存储为对象的属性或 ECMAScript 语言变量的值。

在本规范中,符号 “Type(x)” 用作 “x 的类型” 的简写,其中 “type” 指的是本节中定义的 ECMAScript 语言和规范类型。

规范 11.9.3 抽象等式(==)比较算法

比较 x == y,其中 xy,结果为 true 或者 false。这样的比较执行如下:

x 和 y 类型相同的情况

1. 如果 x 的类型 与 y 的类型 相同,那么
    a. 如果 Type(x) 为 Undefined, return true
    b. 如果 Type(x) 为 Null, return true
    c. 如果 Type(x) 为 Number, 那么
          i. 如果 x 是 NaN, return false
         ii. 如果 y 是 NaN, return false
        iii. 如果 x 和 y 的值相等,return true
         iv. 如果 x 是 +0, y 是 -0, return true
          v. 如果 x 是 -0, y 是 +0, return true
         vi. 其他的情况 return false
    d. 如果 Type(x) 为 String,则如果 x 和 y 是完全相同的字符序列(长度相同且相应位置的字符相同),则返回 true。 否则,返回 false。
    e. 如果 Type(x) 为 Boolean,则当 x 和 y 均为 true 或均为 false 时返回 true。 否则,返回 false。
    f. 如果 x 和 y 引用同一个对象,则返回 true; 否则,返回 false。

x 和 y 类型不相同的情况

2. 如果 x 为 null,y 为 undefined, return true
3. 如果 x 为 undefined,y 为 null, return true

4. 如果 Type(x) 为 Number, Type(y) 为 String,return x == ToNumber(y)
5. 如果 Type(x) 为 String, Type(y) 为 Number,return ToNumber(x) == y

6. 如果 Type(x) 为 Boolean,return ToNumber(x) == y
7. 如果 Type(y) 为 Boolean,return x == ToNumber(y)

8. 如果 Type(x) 为 String 或者 Number,Type(y) 为 Object, return x == ToPrimitive(y)
9. 如果 Type(x) 为 Object,Type(x) 为 String 或者 Number,return ToPrimitive(x) == y

10. 其他情况返回 false

== 比较算法原文

image.png

根据上面的算法,我们来看下最开始的问题, 为什么 [] == ![]true

分析:

  1. ![] 得到的是一个 Boolean 类型的值 false , 就相当于是 [] == false,需要应用第 7 条,得到的结果比较 [] == 0

  2. [] 的类型是 Object, 0 的类型是 Number,应用第 9 条规则,ToPrimitive([]) == 0,得到结果比较 "" == 0

  3. 接上条,Type(x) 为 String,Type(y) 为 Number,应用第5条规则,需要将 x 变成数字再与 y 比较,即 ToNumber('') == 0, 最后得到的比较就是比较 00

  4. 于是,根据 1-c-iii,结果为 true。

ToNumber() 和 ToPrimitive()

我们看到规范中,有提到 ToPrimitive()ToNumber(),那么它们背后的原理分别是什么呢?

篇幅有些长,会在其他的文章中,单独拿出来说明。感兴趣的可以访问

262.ecma-international.org/5.1/#sec-9.…

262.ecma-international.org/5.1/#sec-9.…

用图表表示 == 算法

为了更好的对照,我根据规范画了流程图

image.png

image.png