例如:
+[]===0
-[]===0
~[]===-1
~-~[]===-2
~-~-~-~-~[]===-5
~-~-~-~-~[]+~[]===-6
~+~[]===0
~+~+~[]===-1
~+~+~+~[]===0
+[]===0
-[]===0
~[]===-1
~-~[]===-2
~-~-~-~-~[]===-5
~-~-~-~-~[]+~[]===-6
~+~[]===0
~+~+~[]===-1
~+~+~+~[]===0
[]
是一个空数组对象,因此:
+[]: 强制将空数组转换为正整数0,即 === 0
-[]: 强制将空数组转换为负整数0,即 === 0
~[]: 对空数组进行按位取反运算,得到-1,即 === -1
~-~[]: 对取反两次的空数组进行按位取反运算:~-(-1) -> ~1 -> -2
等等...
~1 -> -2
- Denis+[]: 强制空数组成为正整数,即0,与0相等
并没有解释为什么会发生这种情况。它只是重申了结果。显然,如果 +[] === 0
,那么 +[]
必须已经被转换为 0
。该问题要求解释逻辑。 - RightSaidFred+
或-
运算符时,它会调用Number
。 Number([])
返回0
,所以你得到了前两个答案。
~
运算符是按位取反。基本上它会将一个数字中的所有位取反,从而将0
变为-1
。更多关于按位运算符的信息请参考这里。[]
转换为0
的部分。 - Denis不仅要重新陈述你在问题中展示的结果,我还会尝试描述为什么会得到那个结果。
解释
只考虑第一个例子(因为其余的情况类似),我们可以按照规范来看看会发生什么。
从11.4.6 一元加操作符我们可以看到进行了 ToNumber
转换。
返回 ToNumber(GetValue(expr))。
从9.3 ToNumber中我们可以看到,如果给定一个对象(如您的数组),则会进行一个 ToPrimitive
转换,然后再尝试进行 ToNumber
转换。
对象
执行以下步骤:
- 将 primValue 设置为 ToPrimitive(输入参数,提示数字)的结果。
- 返回 ToNumber(primValue) 的结果。
从9.1 To Primitive中,如果 ToPrimitive
得到了一个对象,我们可以看到它的 [[DefaultValue]]
将被获取:
对象
返回对象的默认值。通过调用对象的 [[DefaultValue]] 内部方法,传递可选的提示 PreferredType 来检索对象的默认值。对于 8.12.8 中的所有本机 ECMAScript 对象,[[DefaultValue]] 内部方法的行为由本规范定义。
从8.12.8 [[DefaultValue]](提示)中,最终发生的是调用数组的 toString()
并返回它的字符串。这个字符串将被发送到上述递归的 ToNumber
中。
那么在字符串上执行 ToNumber
转换会发生什么呢?在9.3.1 应用于字符串类型的 ToNumber中有详细说明,但有点冗长。简单地直接进行转换可以看出会发生什么:
Number(""); // result is 0 on an empty string
Number(" "); // result is 0 on a string with only whitespace
Number("123"); // result is 123 on a numeric string
Number(" 123 ");// result is 123 on a numeric string with leading & trailing spaces
Number("abc"); // result is NaN (not a number) on non-numeric strings
那么问题来了,我们从数组中得到的字符串是什么?这很容易测试。
[].toString(); // result is "" (empty string)
由于结果是一个空字符串,而根据上面所示的规则,将空字符串进行 ToNumber
转换后得到的值为 0
,这意味着我们在比较 0 === 0
。
这与我们执行以下代码的效果相同:
Number( [].toString() ) === 0; // true
var x = [];
x = x.toString(); // ""
x = Number( x ); // 0
x === 0; // true
更多 toString
的结果。
为了展示数组更多的toString
转换,考虑以下内容:
[1].toString(); // "1"
[1,2,3].toString(); // "1,2,3"
["a",1,"b",2].toString(); // "a,1,b,2"
对于上面的数组进行 ToNumber
转换,第一个将给我们一个数字,而后两个将导致 NaN
。
Number([1]); // 1
Number([1,2,3]); // NaN
Number(["a",1,"b",2]); // NaN
一些证明
为了进一步证明在ToNumber
转换之前发生toString()
转换,我们可以修改Array.prototype.toString
以提供不同的结果,任何ToNumber
转换都将使用该修改后的结果。
Array.prototype.toString = function() {
var n = 0;
for( var i = 0; i < this.length; i++ ) {
n += this[i];
}
return n;
};
在这里,我已经用一个将数组求和的函数替换了Array.prototype
上的toString
。显然,你不想这样做,但我们可以展示现在会得到不同的结果。
Number([1,2,3]); // 6
+[1,2,3]; // 6
现在你可以看到,我们之前会得到NaN
的数组的ToNumber
转换现在将得到数组中所有项的总和。
我会尽力而为:
[]===0
当然是假的,因为[]
不等于0。然而,[]==0
是真的,因为存在隐式转换。
+
和-[]
有效,因为加或减将[]
转换为实数。
~0
(0的按位反转)是-1。因此,~[]===-1
有效。
其他的都是通过多次加或减-1来实现的。
我相信,如果我错了,请纠正我,但是将值添加到数组中(例如,将一个值添加到数组中而不是将一个值添加到数组中)会将其转换为数字。其余部分只是使用基本的“+”、“-”运算符(波浪线(~)表示按位取反)修改数字,然后进行等式计算。
So [] == array ([]);
[] + 1 == number (0);
+[]===0 (true)
[1] + 1 = "11"
所以 +[] = 0
因为这就像执行 +""
。 - pleasedontbelong
+[NaN]==!!!!0&&+[{}]+~~[[]]-[]
- jAndy