本文原创:zhangchao
在面试时,我们有时候会遇到这样的题
[] + {} = ?[] == ![]的输出结果是什么
其实这都是在考察我们对于隐式转换的掌握情况。
隐式转换主要用到了JavaScript引擎内部的抽象操作toPrimitive,ToPrimitive()有着这样的签名: ToPrimitive(input, PreferredType?)
可选参数PreferredType可以是Number或者String,它只代表了一个转换的偏好,转换结果不一定必须是这个参数所指的类型,但转换结果一定是一个原始值。如果PreferredType被省略,除Date类型的值采用String,其他类型的值采用Number。
我们先来看看当PreferredType = Number,值的转化过程如下
如果输入Input是基本类型, 就返回这个值
如果输入变量是Object类型, 那么调用input.valueOf(). 如果返回结果是基本类型,就返回这个指
如果都不是的话就调用input.toString(). 如果结果是基本类型, 就返回它
如果以上都不可以,就会抛出一个类型错误TypeError, 表示转化input变量到基本类型失败。
当PreferredType = String时,只需要将步骤2和步骤3调换顺序即可。
要分析第一个面试题,我们还要了解加号运算符的定义是这样的:如果其中一个是字符串,另一个也会被转换为字符串,否则两个运算数都被转换为数字。
到目前为止,我们可以分析一下第一个面试题[] + {} = ?
ToPrimitive([])操作,PreferredType被省略,默认Number,走
PreferredType = Number逻辑。input = [],执行input.valueOf()后还是数组
继续执行[].toString(),得到""(空字符串),返回
根据加号运算符的定义,{}转换为字符串得到"[object Object]"。
字符串相加,"" + "[object Object]" = "[object Object]"
所以最终结果为[] + {} = "[object Object]"
接下来我们在看下宽松相等(==)。
在了解宽松相等前,我们先来介绍一下全等操作符(===)。
在MDN上的定义:全等操作符比较两个值是否相等,两个被比较的值在比较前都不进行隐式转换。如果两个被比较的值具有不同的类型,这两个值是不全等的。否则,如果两个被比较的值类型相同,值也相同,并且都不是 number 类型时,两个值全等。最后,如果两个值都是 number 类型,当两个都不是 NaN,并且数值相同,或是两个值分别为 +0 和 -0 时,两个值被认为是全等的。
而宽松相等(==)会先将左右两两边的值转化成相同的原始类型,然后再去比较他们是否相等。在转化之后(==一边或两边都需要转化),最后的相等匹配会像===符号一样去执行判断。
宽松相等操作符对于不同类型的值,进行的比较如下图所示
(图1-转换规则,来源于MDN,查看)
ToNumber从字面上就可以理解,将参数转换为数字。规则如下:
| 参数 | 结果 |
|---|---|
| undefined | NaN |
| Null | +0 |
| Boolean | true被转换为1,false转换为+0 |
| Number | 无需转换 |
| String | 由字符串解析为数字.例如,"324"被转换为324 |
这时我们再来分析一下第二道面试题[] == ![]的输出结果是什么
按照运算符优先级,会先执行逻辑非(!),!会将变量转换为Boolean类型,我们知道其值为 0、-0、null、false、NaN、undefined、或者空字符串(""),则生成的 Boolean 对象的值为 false。所以,![] => !new Boolean([]) => !true => false
对照图1,使用ToPrimitive(A) == ToNumber(B)
A = [],执行ToPrimitive(A),得到"" == 0
再根据图1,使用ToNumber(A) === B
A = "",执行ToNumber(A),得到0
最后0 === 0,为true
最后,大家再思考一下{} + []的计算结果是什么?
欢迎计算机前端相关领域小伙伴加入我们,具体的招聘信息可进入公众号查看,欢迎关注。

本文由博客一文多发平台 OpenWrite 发布!