解析 ++[[]][+[]]+[+[]] 返回字符串 "10" 的原因
解析 ++[[]][+[]]+[+[]] 返回字符串 “10” 的原因
技术背景
在 JavaScript 中,运算符和数据类型的隐式转换规则较为复杂。++[[]][+[]]+[+[]]
这个表达式就是一个很好的例子,它涉及到数组、一元运算符、前置递增运算符以及加法运算符的组合,同时伴随着多次的数据类型转换。理解这类复杂表达式的求值过程,有助于我们深入掌握 JavaScript 的语言特性。
实现步骤
1. 解析 +[]
在 JavaScript 中,+
作为一元运算符时,会尝试将其操作数转换为数字类型。对于空数组 []
,转换过程如下:
- 首先,根据规范,
+
运算符会调用ToNumber
方法将操作数转换为数字。对于对象类型(数组属于对象),会先调用ToPrimitive
方法将其转换为原始值,并且提示类型为String
。 ToPrimitive
方法会调用对象的[[DefaultValue]]
内部方法。对于数组,[[DefaultValue]]
方法会先尝试调用toString
方法。而数组的toString
方法实际上是调用join
方法,空数组调用join
方法会返回空字符串""
。- 最后,
ToNumber
方法将空字符串""
转换为数字0
,所以+[] === 0
。
2. 简化表达式为 ++[[]][0] + [0]
因为 +[]
等于 0
,所以原表达式 ++[[]][+[]]+[+[]]
可简化为 ++[[]][0] + [0]
。[[]][0]
表示从数组 [[]]
中获取第一个元素,即内部的空数组 []
。
3. 解析 ++[[]][0]
++
是前置递增运算符,它会先将操作数转换为数字,然后加 1,并返回递增后的结果。这里 [[]][0]
得到的空数组 []
会被转换为数字 0
,然后加 1,最终结果为 1
。
4. 解析 1 + [0]
当加法运算符 +
的两个操作数一个是数字,一个是数组时,会先将数组转换为字符串。数组 [0]
转换为字符串后是 "0"
,然后数字 1
也会被转换为字符串 "1"
,最后进行字符串拼接,得到 "10"
。
核心代码
1 |
|
最佳实践
虽然这类复杂的表达式在实际开发中很少使用,但理解其求值过程有助于我们编写更健壮的代码。在实际开发中,应尽量避免使用过于复杂的隐式类型转换,明确指定数据类型的转换,以提高代码的可读性和可维护性。例如:
1 |
|
常见问题
1. 为什么 ++[]
会报错?
++
运算符用于递增变量或对象属性的值,它不仅要计算新值,还要将新值存储回去。而 ++[]
中,空数组没有可以存储新值的引用,因此会报错。
2. 如何改变表达式的结果?
如果重写 Array.prototype
的 toString()
或 valueOf()
方法,会改变对象转换为原始值的结果,从而改变表达式的最终结果。例如:
1 |
|
解析 ++[[]][+[]]+[+[]] 返回字符串 "10" 的原因
https://119291.xyz/posts/explanation-of-plus-plus-array-expression/