JavaScript面试题,为什么[] + 0 = '0', 而{} + 0 = 0?

介绍

昨天在网上看到一道面试题,是关于JavaScript中的+元算符的,如下:

javascript 复制代码
[] + 0 = ?
{} + 0 = ?

要解决这道题,我们首先要了解JavaScript中+运算符的行为,+元算符在JavaScript中主要有三种用途:一是用于数字相加,二是用于字符串连接,三是用于类型转换。

js 复制代码
1 + 2 = 3 // 数字相加
'Hello, ' + 'World!' = 'Hello, World!' // 字符串连接
+'1' = 1 // 字符串转换为数字

再回到面试题,可以看出,这并非常规的加法操作,因为运算符两侧的操作数并非都是数字类型,而是包含了数组和对象。难道是字符串连接吗?不确定,是类型转换?好像也不是。

追本溯源,我们先看看MDN上关于+的运行规则吧:

如果+元算符的操作数包含非基本类型(比如对象,数组等),先将其转换为基本类型(primitive type)。

在JavaScript中,基本类型包括undefinednullbooleannumberstringBigIntSymbol

+元算符两侧都是基本类型时,执行规则如下:

  1. 有一个操作数是字符串时,将另一个操作数也转换为字符串,并执行字符串连接;
  2. 有一个操作数是BigInt时,将另一个操作数也转换为BigInt,并执行加法;
  3. 否则,将两个操作数都转换为数字,并执行加法。

举几个列子:

js 复制代码
1 + `2` = '12' // 满足规则1,将数字1转换为字符串'1',执行字符串连接
1 + 2n = 3n // 满足规则2,将数字1转换为
null + true = 1 // 满足规则3,将null转换为数字0,将true转换为数字1,执行加法

我们这道题不涉及BigInt,所以只需要关注字符串连接和数字加法就好。

现在来看[] + 0该如何执行,首先[]是数组,不属于基本类型,所以先将它转换为基本类型,对象类型转换为基本类型的操作如下:

  1. 调用对象的toPrimitive方法;
  2. 如果没有toPrimitive方法,则调用valueOf方法;
  3. 如果valueOf方法返回的值不是基本类型,则调用toString方法;
  4. 如果toString方法返回的值仍不是基本类型,则抛出错误。

所以[] + 0的执行过程如下:

  1. []没有toPrimitive方法,所以调用valueOf方法。
  2. valueOf方法返回值仍然是数组对象[]
  3. 接着调用toString方法,返回空字符串''

因此,[] + 0等价于'' + 0, 此时+两侧都是基本类型了,并且满足有一侧是字符串的条件,所以将另一侧的操作数0也转换为字符串,执行字符串连接,结果为'' + '0' = '0'

再来看{} + 0, {}[]一样,都是对象类型,所以先将其转换为基本类型。

  1. {}没有toPrimitive方法,所以调用valueOf方法,返回值仍然是对象{}
  2. 接着调用toString方法,返回字符串'[object Object]'
  3. 然后将'[object Object]'0进行字符串连接,结果为'[object Object]' + '0' = '[object Object]0'

哈哈,但是我要告诉你,这个答案是错误的,这个分析是没有问题的,但是JavaScript解释器不同意,当它看到{}时,会将其解释为一个空的代码块,而不是一个空对象,因此,{} + 实际上等于下面的代码:

javascript 复制代码
{}
+ 0

这时,而{}被视为一个空代码块, 没有返回任何结果,而+ 0被解释为一条独立的语句,返回值是0,最终结果是0

如果要让代码按照我们上面分析的过程执行,那么就要防止JavaScript将{}解释为空代码块,可以用()将其包裹起来。

javascript 复制代码
({}) + 0 // 结果为 '[object Object]0'

总结

js 复制代码
[] + 0 = '0'
{} + 0 = 0

说实话这道题目比较偏门,但是对于了解JavaScript中+运算符的行为还是很有帮助的,通过一道题,能了解一个知识点,还是很值得的。

有的时候,不要光纠结问题的答案,更应该关注的是问题背后的原理的规则,就比如这道题,在没有写这篇文章之前,如果让我回答,我是答不上来的,我需要查阅资料,了解+运算符的行为规则,才能得出正确的答案。我觉得相比知道答案,更有意思的是分析的过程,这个过程体现了一个程序员处理问题的逻辑思维能力,小到一道面试题,大到一个复杂的系统设计,都是如此。那么如何培养这种能力呢,我也一直在寻找答案...

今天就到这里了,我们明天见。

今天周六,准备出去逛逛,奈何天气太热,动也不想动,只能呆在家里了。锁凤十代打了两天,手感非常不错,准备留下了,之前买的猛禽就退了吧,现在赚钱不易,还是要精打细算的好。

相关推荐
用户18729422508392 分钟前
告别函数的“两面派”人生:深度剖析箭头函数如何一劳永逸地解决 ‘this’ 的二义性
javascript
拉不动的猪3 分钟前
关于scoped样式隔离原理和失效情况&&常见样式隔离方案
前端·javascript·面试
鹏北海27 分钟前
Vue 3 超强二维码识别:多区域/多尺度扫描 + 高级图像处理
前端·javascript·vue.js
Jack莱杰27 分钟前
Math.js封装工具库(解决前端因为浮点数导致计算错误)
javascript
Android疑难杂症29 分钟前
一文讲清鸿蒙网络开发
前端·javascript·harmonyos
爱学习的程序媛31 分钟前
【JavaScript基础】Null类型详解
前端·javascript
网络点点滴1 小时前
watch监视-ref基本类型数据
前端·javascript·vue.js
大布布将军1 小时前
《前端九阴真经》
前端·javascript·经验分享·程序人生·前端框架·1024程序员节
幸运小圣1 小时前
for...of vs for 循环全面对比【前端JS】
开发语言·前端·javascript
_志哥_2 小时前
深度解析:解决 backdrop-filter 与 border-radius 的圆角漏光问题
前端·javascript·html