JavaScript 面试题,为什么 [] + 0 = '0', 而{} + 0 = 0?
介绍
昨天在网上看到一道面试题,是关于 JavaScript 中的+
元算符的,如下:
要解决这道题,我们首先要了解 JavaScript 中+
运算符的行为,+
元算符在 JavaScript 中主要有三种用途:一是用于数字相加,二是用于字符串连接,三是用于类型转换。
再回到面试题,可以看出,这并非常规的加法操作,因为运算符两侧的操作数并非都是数字类型,而是包含了数组和对象。难道是字符串连接吗?不确定,是类型转换?好像也不是。
追本溯源,我们先看看 MDN 上关于+
的运行规则吧:
如果+
元算符的操作数包含非基本类型(比如对象,数组等),先将其转换为基本类型(primitive type)。
在 JavaScript 中,基本类型包括
undefined
、null
、boolean
、number
、string
、BigInt
、Symbol
。
当+
元算符两侧都是基本类型时,执行规则如下:
有一个操作数是字符串时,将另一个操作数也转换为字符串,并执行字符串连接;
如果两个操作数都是
BigInt
,按BigInt
执行加法操作,如果一个操作书是BigInt
,而另一个不是,则抛出TypeError错误。否则,将两个操作数都转换为数字,并执行加法。
举几个列子:
注意以上 3 条规则是按顺序执行的,字符串连接的优先级高于数字加法,所以字符串和数字相加时,永远会转换为字符串连接。
现在来看[] + 0
该如何执行,首先[]
是数组,不属于基本类型,所以先将它转换为基本类型,对象类型转换为基本类型的操作如下:
调用对象的
toPrimitive
方法;如果没有
toPrimitive
方法,则调用valueOf
方法;如果
valueOf
方法返回的值不是基本类型,则调用toString
方法;如果
toString
方法返回的值仍不是基本类型,则抛出错误。
所以[] + 0
的执行过程如下:
[]
没有toPrimitive
方法,所以调用valueOf
方法。valueOf
方法返回值仍然是数组对象[]
。接着调用
toString
方法,返回空字符串''
。
因此,[] + 0
等价于'' + 0
, 此时+
两侧都是基本类型了,并且满足有一侧是字符串的条件,所以将另一侧的操作数0
也转换为字符串,执行字符串连接,结果为'' + '0'
= '0'
。
再来看{} + 0
, {}
和[]
一样,都是对象类型,所以先将其转换为基本类型。
{}
没有toPrimitive
方法,所以调用valueOf
方法,返回值仍然是对象{}
。接着调用
toString
方法,返回字符串'[object Object]'
然后将
'[object Object]'
与0
进行字符串连接,结果为'[object Object]' + '0'
='[object Object]0'
。
哈哈,但是我要告诉你,这个答案是错误的,这个分析是没有问题的,但是 JavaScript 解释器不同意,当它看到{}
时,会将其解释为一个空的代码块,而不是一个空对象,因此,{} + 0
实际上等于下面的代码:
{}
被视为一个空代码块, 没有返回任何结果,而+ 0
被解释为一条独立的语句,返回值是 0,最终结果是0
。
如果要让代码按照我们上面分析的过程执行,那么就要防止 JavaScript 将{}
解释为空代码块,可以用()
将其包裹起来。
总结
说实话这道题目比较偏门,但是对于了解 JavaScript 中+
运算符的行为还是很有帮助的,通过一道题,能了解一个知识点,还是很值得的。
有的时候,不要光纠结问题的答案,更应该关注的是问题背后的原理的规则,就比如这道题,在没有写这篇文章之前,如果让我回答,我是答不上来的,我需要查阅资料,了解+
运算符的行为规则,才能得出正确的答案。我觉得相比知道答案,更有意思的是分析的过程,这个过程体现了一个程序员处理问题的逻辑思维能力,小到一道面试题,大到一个复杂的系统设计,都是如此。那么如何培养这种能力呢,我也一直在寻找答案...
最后给大家留几道思考题:
文章转载自:前端风云志
评论