[]==![] js隐式转换核心原理

480 阅读2分钟

引题

此处暂停30秒,把答案记在心理。打开控制台看看结果吧。
没错,答案是true

image.png

剖析一下,主要分为:

  1. 逻辑运算符的优先级;
  2. {}[]复杂数据在做运算比较时类型如何转换(隐式转换); 逻辑运算符这个比较简单,不多讲,可以参考运算符优先级-mdn
    接下来就是js的隐式转换
    首先,回想一下JS的类型都有什么:

原始值(primitives): undefined、null、Boolean、Number、String、Symbol、Bigint
对象值(objects): Object(包含数组、正则、对象、方法等)

ok, 这就是全部了,我们接下来看看到底发生了什么导致隐式转换如此不可捉摸。

ECMAScript规范

既然要搞懂,就得看去看ECMAScript规范里面==是如何操作的传送门

image.png

重点看对象值,里面ToPrimitive ToPrimitive就是转换成原始值,然后我们再看下ToPrimitive里面操作:

image.png image.png 简单解读一下,大概意思就是:

  1. value为原始值,直接返回;

  2. 不是原始值,调用该对象的valueOf()方法,如果结果是原始值,返回原始值;

  3. 调用valueOf()不是原始值,调用此对象的toString()方法,如果结果为原始值,返回原始值;

  4. 如果返回的不是原始值,抛出异常TypeError
    我们知道隐式转换规则了,那我们再来看 :[]==![]

  5. []不是原始值,调用对象相关的 valueOf()

image.png
2. 调用valuerOf()过后返回的还是 [],所以继续调用对象的toString()

image.png

  1. 调用toString()过后返回''
  2. 逻辑运算符:![] 的值是 false
  3. 隐式转换过后:'' == ![] ==〉'' == false
    现在就是字符串和布尔相比较了,答案直接出来不是。
    等等 。 '' == false 也没有是两个相等的值比较啊,这肯定也需要转换的。

MDN 非严格相等

看下mdn怎么说非严格相等-mdn传送门

引用mdn原话:相等操作符比较两个值是否相等,在比较前将两个被比较的值转换为相同类型。在转换后(等式的一边或两边都可能被转换),最终的比较方式等同于全等操作符 === 的比较方式。 相等操作符满足交换律。

image.png
String和Boolean 比较都会通过ToNumber转换过后再 === 比较。

image.png
整个隐式转换的过程就完成了。

小试牛刀

如何实现a==1&&a==2&&a==3true?
方案1: 重写对象的valueOf()

const a = {
    b: 0,
    valueOf() {
        return ++this.b;
    }
}
if (a == 1 && a == 2 && a == 3) {
    console.log(true);
}

方案2: 上面我们说过,对象值在进行比较时会先调用valueOf(),调用valueOf()不是原始值,调用此对象的toString()方法,所以我们也可以重写toString()

const a = {
    b: 0,
    toString() {
        return ++this.b;
    }
}
if (a == 1 && a == 2 && a == 3) {
    console.log(true);
}

当然,还有其他的方案,这里不做探究。