js基础-隐式转换

603 阅读3分钟

本文原创:zhangchao

在面试时,我们有时候会遇到这样的题

  1. [] + {} = ?

  2. [] == ![]的输出结果是什么

其实这都是在考察我们对于隐式转换的掌握情况。

隐式转换主要用到了JavaScript引擎内部的抽象操作toPrimitive,ToPrimitive()有着这样的签名: ToPrimitive(input, PreferredType?)

可选参数PreferredType可以是Number或者String,它只代表了一个转换的偏好,转换结果不一定必须是这个参数所指的类型,但转换结果一定是一个原始值。如果PreferredType被省略,除Date类型的值采用String,其他类型的值采用Number。

我们先来看看当PreferredType = Number,值的转化过程如下

  1. 如果输入Input是基本类型, 就返回这个值

  2. 如果输入变量是Object类型, 那么调用input.valueOf(). 如果返回结果是基本类型,就返回这个指

  3. 如果都不是的话就调用input.toString(). 如果结果是基本类型, 就返回它

  4. 如果以上都不可以,就会抛出一个类型错误TypeError, 表示转化input变量到基本类型失败。

PreferredType = String时,只需要将步骤2和步骤3调换顺序即可。

要分析第一个面试题,我们还要了解加号运算符的定义是这样的:如果其中一个是字符串,另一个也会被转换为字符串,否则两个运算数都被转换为数字。

到目前为止,我们可以分析一下第一个面试题[] + {} = ?

  1. ToPrimitive([])操作,PreferredType被省略,默认Number,走PreferredType = Number逻辑。

  2. input = [],执行input.valueOf()后还是数组

  3. 继续执行[].toString(),得到""(空字符串),返回

  4. 根据加号运算符的定义,{}转换为字符串得到"[object Object]"。

  5. 字符串相加,"" + "[object Object]" = "[object Object]"

所以最终结果为[] + {} = "[object Object]"

接下来我们在看下宽松相等(==)。

在了解宽松相等前,我们先来介绍一下全等操作符(===)。

在MDN上的定义:全等操作符比较两个值是否相等,两个被比较的值在比较前都不进行隐式转换。如果两个被比较的值具有不同的类型,这两个值是不全等的。否则,如果两个被比较的值类型相同,值也相同,并且都不是 number 类型时,两个值全等。最后,如果两个值都是 number 类型,当两个都不是 NaN,并且数值相同,或是两个值分别为 +0 和 -0 时,两个值被认为是全等的。

而宽松相等(==)会先将左右两两边的值转化成相同的原始类型,然后再去比较他们是否相等。在转化之后(==一边或两边都需要转化),最后的相等匹配会像===符号一样去执行判断

宽松相等操作符对于不同类型的值,进行的比较如下图所示

转换.png (图1-转换规则,来源于MDN,查看)

ToNumber从字面上就可以理解,将参数转换为数字。规则如下:

参数 结果
undefined NaN
Null +0
Boolean true被转换为1,false转换为+0
Number 无需转换
String 由字符串解析为数字.例如,"324"被转换为324

这时我们再来分析一下第二道面试题[] == ![]的输出结果是什么

  1. 按照运算符优先级,会先执行逻辑非(!),!会将变量转换为Boolean类型,我们知道其值为 0、-0、null、false、NaN、undefined、或者空字符串(""),则生成的 Boolean 对象的值为 false。所以,![] => !new Boolean([]) => !true => false

  2. 对照图1,使用ToPrimitive(A) == ToNumber(B)

  3. A = [],执行ToPrimitive(A),得到"" == 0

  4. 再根据图1,使用ToNumber(A) === B

  5. A = "",执行ToNumber(A),得到0

  6. 最后0 === 0,为true

最后,大家再思考一下{} + []的计算结果是什么?


欢迎计算机前端相关领域小伙伴加入我们,具体的招聘信息可进入公众号查看,欢迎关注。

关注我们吧.jpg

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