废话不多说,我们先来看第一个例子吧。
某天,我遇到了这样一个问题:给出变量a和b的定义,使下面三个语句的输出结果都为true。

console.log(a<b);
console.log(a==b);
console.log(a>b);

看到题目的我第一反应是懵逼的,还有这样的操作???然后一开始的思路是往各种神奇的值上面找,比如undefined,null,NaN,“”这样的值,自然是没有得到想要的结果了。
但事实上,真的存在。来看代码:

function A(){
    this.a = 1;
}

A.prototype = {
    toString: function(){
        return this.a += 2;
    }
}

var a = new A();
var b = 5;
console.log(a < b);
console.log(a == b);
console.log(a > b);

上面的代码不难理解:变量a是通过构造函数A创建的对象,变量b就是一个很简单的数值。一开始,因为a是通过构造函数A创建的对象,所以值为1.然后每一次在执行 console.log()的时候,会调用一次A的toString方法。所以,在第一个console.log()的时候,a的值变成了3,而b的值是5,所以a<btrue;第二个console.log()的时候,a的值变成了5,而b的值还是5,所以a=btrue;第三个console.log()的时候,a的值变成了7,而b的值依旧是5,所以a>btrue
经过上面的分析,我们似乎打开了一个新世界的大门,这里涉及到一个比较重要的概念:隐式类型转换。在上面的例子里,a和b是两个完全不一样的类型,但是它们进行了比较,还得出了结果,这就说明有一个类型在比较的过程中转换成了另一个类型。
这里需要提到一些规范来帮助我们更好的理解。
(小于大于的比较规则和相等是一样的。)
对于字符串和数字来说,ES5规范11.9.3.4.5这样规定:

(1)如果Type(x)是数字,Type(y)是字符串,则返回x == ToNumber(y)的结果
(2)如果Type(x)是字符串,Type(y)是数字,则返回ToNumber(x) == y的结果

对于其他类型和布尔类型的比较,规范11.9.3.6.7这样规定:

(1)如果Type(x)是布尔类型,则返回ToNumber(x) == y的结果
(2)如果Type(y)是布尔类型,则返回x == ToNumber(y)的结果

对于null和undefined来说,ES5规范11.9.3.2.3这样规定:

(1)如果x为null,y为undefined,则结果为x == y
(2)如果x为undefined,y为null,则结果为x == y

也就是说,null和undefined是相等的。
对于对象和非对象来说,ES5规范11.9.3.8.9这样规定:

(1)如果Type(x)是字符串或数字,Type(y)是对象,则返回x == ToPrimitive(y)的结果
(2)如果Type(x)是对象,Type(y)是字符串或数字,则返回ToPrimitive(x) == y的结果

基本就是上面这几种常见的类型的比较了。然后出现了一个我们好像不太常见的东西:ToPrimitive()这个方法。我们来简单了解一下:
对象(或者数组)再进行比较或者类型转换的时候,先会被转换为相应的基本类型值,然后再根据需要进行转换。再转换为基本类型值的时候,抽象操作ToPrimitive会先检查该值是否拥有valueOf()方法。如果有且返回基本类型值,就使用该值作为基本类型值,如果没有就使用toString()方法的返回值作为基本类型值。
上面例子中的相等操作我们使用了==,而不是===。对于这二者的区别,我们经常听到的是,==是不严格相等,只要值相等即可,而===是严格相等,必须值和类型都相等才可以。对于==来说,类型不重要,也就是说在这个过程中是包含了类型转换的。所以,在YouDontKnowJS这本书中,给出的正确解释是:

==允许在相等比较总进行强制类型转换,而===不允许。

然后我们再来看第二个例子吧
题目是这样的:[1]+[2]-[3]=?
这次打算先分析再给出答案,顺便大家也可以自己想想结果是什么。
首先我们看到加减运算符左右两边的值都是数组,那前面提到过对于数组的处理。因为数组的valueOf()操作无法得到简单的基本类型值,所以会调用toString(),这样的话上面那个式子就变成了"1"+"2"-"3"=?。现在这个式子相信大家都比较熟悉了,不过不知道会不会有人一时头脑发热,把答案想成了0。
然后我们继续往下,因为是加减操作符,所以我们从左至右开始计算,"1"+"2"这个结果到底是3还是12呢。那就记住简单的一句话:如果有一个值是字符串,那么就进行字符串拼接,否则进行数字加法。那么很明显,这里是2个字符串,进行字符串拼接,得到"12"
好了,到目前为止,式子已经变成了"12"-"3"了,这应该已经很明显了吧,字符串拼接是肯定不可能的,那就是进行数字运算了,那就是最简单的12-3了,所以最终结果就是9。
其实这个例子里的通过加减运算符进行隐式类型转换在我们日常代码中经常出现,只是可能大家没有特别关注,比如a + ""是把a转换为字符串;a - 0是把a转换为数字。


Uniquec
22 声望3 粉丝