使用运算符作为变量会产生奇怪的结果。
使用运算符作为变量会产生奇怪的结果。这个问题的出现原因是由于对运算符的使用顺序不清楚。解决方法是通过查看语法解析器的解析结果来确定运算符的使用顺序。例如,可以使用https://astexplorer.net/来查看第一个示例的解析结果,即! + [] === true
使用了一元逻辑非运算符(!
)、一元加法运算符(+
)、一个空的数组字面量([]
)、严格相等运算符(===
)和真值关键字(true
)。
执行顺序是(!(+[])) === true
,或者可以看作是以下树状结构:
=== / \ ! true | + | []
接下来需要理解每个运算符对其操作数进行的转换。首先看一元加法运算符+
和操作数[]
。它对操作数执行ToNumber
操作,对于像[]
这样的对象,会先执行ToPrimitive
再执行ToNumber
。ToPrimitive
会尝试调用valueOf
(由于不返回原始值,所以不会使用)和toString
。对于数组来说,toString
会查找join
函数并以没有参数的方式调用它(将数组作为this
)。对于空数组来说,这将导致空字符串""
,并通过后续的ToNumber
转换为0
。
接下来是一元逻辑非运算符,它首先将操作数转换为布尔值。对于操作数0
,转换结果为false
。然后,返回相反的值,即true
。
最后,我们知道true === true
的结果是true
。
有趣的是,这里使用了Array.prototype.join
的默认情况。我相信很多人会对为什么修改join
会影响结果感到惊讶。
其他示例的工作方式类似:
- (! + '')
几乎相同,只是ToNumber
不需要之前的ToPrimitive
- 对于(!'')
,空字符串的ToBoolean
结果为false
,因此结果为true
- 对于(![])
,任何对象的ToBoolean
结果为true
,因此结果为false
问题的原因是JavaScript在对操作数进行操作时会将其转换为原始类型。对于! + []
这个表达式,它会将+[]
转换为字符串,结果是""
,然后因为!
的存在,它会将其转换为布尔值。在JavaScript中,""
被视为false
。所以最终会返回!false
,即true
。
解决方法是使用其他方式来实现相同的操作,避免使用操作符作为变量。可以参考下面的代码示例:
var emptyBrackets = [].toString(); // 转换为字符串 console.log(emptyBrackets === ''); // 转换为数字 console.log(+emptyBrackets); // 转换为布尔值 console.log(!0);
以上代码可以帮助理解对象转换为原始类型的过程。
对于问题中提到的+
操作符用于将字符串转换为数字的问题,可以参考上面的代码示例进行验证:+"" === 0
。
总结一下,问题的原因是JavaScript在操作操作数时会进行自动类型转换,解决方法是避免使用操作符作为变量,可以通过其他方式来实现相同的操作。