因为沸点有字数限制, 所以用文章来解读
blog 授权: creativecommons.org/licenses/by…
我会从 ECMAScript 规范的层面来解读这个问题.
首先是 + 这个操作符, 来看一下规范是怎么说的

The unary + operator converts its operand to Number type.
译: unary + 操作符转换其的操作对象到 Number 类型.
在随后的算法中调用了 ToNumber 这个抽象行为.
来看一下 ToNumber 做了什么
其将参数转换成 Number 类型根据该表:

显然 [] 是一个对象, 根据表格中对于 Object 的约定, 第一步去调用 ToPrimitive([], hint Number)
来看一下 ToPrimitive 做了什么
其会调用对象上的 @@toPrimitive 方法, 注意一点, Array.prototype 没有实现 @@toPrimitive 方法, Date.prototype 实现了, 感兴趣可以看一下.
所以在 ToPrimitive 算法的 2.g 中调用了 OrdinaryToPrimitive([], hint Number)
来看一下 OrdinaryToPrimitive 做了什么
在该算法中, 会根据 hint 的不同做不同的行为, 这里的 hint 是 'number', 定义 methodNames 为 ["valueOf", "toString"]
Note: 如果 hint 是 'string' 的话, 那么 methodNames 为 ["toString", "valueOf"]
按照 methodNames 的顺序进行调用:
-
[].valueOf()注意, Array.prototype 没有实现 valueOf 方法, 是继承自 Object.prototype 的, 所以我们还需要看一下 Object.prototype.valueOf 返回了什么 你可以看到其返回了 ToObject(this value), 这里 this 指向的就是
[], 根据 ToObject 的算法, 如果是Object就返回本身, 所以调用[].valueOf()返回的是[]本身. 回到 OrdinaryToPrimitive 算法中, 如果valueOf返回的是一个 Object, 那么就继续调用toString -
[].toString(), 注意, Array.prototype 实现了 toString 的方法, 所以这里调用的是Array.prototype.toString, 看一下Array.prototype.toString做了什么, 其实就是调用了
Array.prototype.join,join方法我不再赘述, 空数据会返回一个空字符串'', OK, 回到 OrdinaryToPrimitive 算法中,''空字符串不再是 Object, 将其返回
回退
OrdinaryToPrimitive 返回了 空字符串 '' 给 ToPrimitive
ToPrimitive 返回了空字符串 '' 给 ToNumber
继续 ToNumber

再次调用 ToNumber, 将 '' 空字符串传入
进入 字符串转 Number 的算法

在这里有这么一句话, 如果一个 StringNumericalLiteral 是空的或者是只有 white space, 其会转换成 +0
ToNumber 返回 0
ToNumber 算法结束, 返回 0
Unary + Operator 返回 0
这个 0 将打印在你的终端或者是浏览器的控制台上.
结语
ECMAScript 对于算法的解释详细程度令人吃惊, 这也是我第一次这么去读规范, 其实不是很费脑子.
基本和 @ygming 在沸点下的评论一致, juejin.cn/pin/6850047…
Thanks ALL! ✅