JavaScript 中的 ~[] 结构如何工作?
我遇到了一段无法解释的有效 JavaScript 代码。 例如:
+[]===0
-[]===0
~[]==-1
~ -~[]==-2
~-~-~-~-~[]==-5
~-~-~-~-~[] +~[]==-6
~+~[]===0
~+~+~[]===-1
~+~+~+~[]===0
你能解释一下这些表达式的逻辑吗?
I've come across a working JavaScript code that I can't explain.
For example:
+[]===0
-[]===0
~[]===-1
~-~[]===-2
~-~-~-~-~[]===-5
~-~-~-~-~[]+~[]===-6
~+~[]===0
~+~+~[]===-1
~+~+~+~[]===0
Can you explain the logic of these expressions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
[]
是一个空数组对象,所以:+[]:强制空数组为正整数,又名 0,即 === 到 0
-[]:强制空数组为负整数,即0,即 === 到 0
~[]: 按位非空数组,计算结果为 -1,即 === 到 -1
~-~[]: 取反的 NOTted 空数组的按位 NOT:
~-(-1) -> 〜1 - > -2
等等...
[]
is an empty array object, so:+[]: force empty array to be positive integer, aka 0, which is === to 0
-[]: force empty array to be negative integer, aka 0, which is === to 0
~[]: bitwise NOT empty array, which evaluates to -1, which is === to -1
~-~[]: bitwise NOT of negated NOTted empty array:
~-(-1) -> ~1 -> -2
etc...
当您对任何内容使用
+
或-
运算符时,它会对其调用Number
。Number([])
返回0
,因此您可以获得前两个答案。~
运算符是按位 NOT。基本上,它反转数字中的所有位,将0
更改为-1
。有关按位运算符的更多信息,请此处。其余的只是这些情况的组合。你几乎可以将这些东西结合起来得到你想要的任何数字。
When you use the
+
or-
operator on anything, it callsNumber
on it.Number([])
returns0
, so you get your first two answers.The
~
operator is bitwise NOT. Basically it inverses all the bits in a number, which changes0
to-1
. More on bitwise operators here.The rest are just combinations of those cases. You can pretty much combine those things to make any number you want.
我不会只是重述您在问题中演示的结果,而是尝试描述您为什么会得到该结果。
解释
仅以第一个示例为例(因为其余示例也会做类似的事情),我们可以按照规范来看看会发生什么。
从 11.4.6 Unary + Operator 中,我们可以看到一个
ToNumber
发生转换。从 9.3 ToNumber 中我们看到,如果给定一个对象(比如你的数组),一个
发生 ToPrimitive
转换,然后再次尝试ToNumber
。从 9.1 到 Primitive,如果
ToPrimitive
得到一个 Object,我们可以看到它的[[DefaultValue]]
已被获取:从8.12.8 [[DefaultValue]](提示)开始,最终会发生的是
toString()
将在数组上调用并返回。如上所述,该字符串被发送到递归ToNumber
。那么当对字符串进行
ToNumber
转换时会发生什么?嗯,它在9.3.1 ToNumber Applied to the String Type中进行了描述,并且有点长。更简单的是直接进行转换,然后看看会发生什么:所以问题是,我们从数组中返回什么字符串。同样,这很容易测试。
由于结果是一个空字符串,并且空字符串的
ToNumber
转换为0
(如上所示),这意味着我们正在比较0 === 0
。这将与我们所做的相同:
或者将其绘制得更多一些:
更多
toString
结果。显示更多
toString
转换对于数组,请考虑以下事项:因此,要对上述数组进行
ToNumber
转换,第一个将为我们提供一个数字,最后两个将导致NaN
。一些证明
为了进一步证明此
toString()
转换发生在ToNumber
转换之前,我们实际上可以修改Array.prototype。 toString
提供不同的结果,任何ToNumber
转换都将使用修改后的结果。在这里,我将 Array.prototype 上的 toString 替换为对数组求和的函数。显然您不想这样做,但我们可以展示现在如何获得不同的结果。
现在您可以看到,之前会导致
NaN
的数组的ToNumber
转换现在会导致数组中各项的总和。Instead of just restating the result you demonstrated in the question, I'll try to give a description of why you get that result.
Explanation
Taking only the first example (because the rest will do something similar), we can follow the specification to see what happens.
From 11.4.6 Unary + Operator, we can see that a
ToNumber
conversion takes place.From 9.3 ToNumber we see that if given an Object (like your Array), a
ToPrimitive
conversion takes place followed by another attempt atToNumber
.From 9.1 To Primitive, if
ToPrimitive
gets an Object, we can see that its[[DefaultValue]]
is fetched:From 8.12.8 [[DefaultValue]] (hint), what will ultimately happen will be that
toString()
will be called on the Array, and returned. This string gets sent to the recursiveToNumber
as described above.So what happens when
ToNumber
conversion is done on a String? Well it is described in 9.3.1 ToNumber Applied to the String Type, and is a bit lengthy. Simpler is to just do the conversion directly, and see what happens:So the question is, what string do we get back from our Array. Again, this is easy to simply test.
Since the result is an empty string, and a
ToNumber
conversion of an empty string is0
as shown above, that would mean we are comparing0 === 0
.It would be the same as if we did:
Or to draw it out a bit more:
More
toString
results.To show more
toString
conversions of Arrays, consider the following:So to do a
ToNumber
conversion on the above Arrays, the first would give us a number, and the last two would result inNaN
.Some proof
To provide further proof that this
toString()
conversion happens before theToNumber
conversion, we can actually modifyArray.prototype.toString
to provide a different result, and anyToNumber
conversions will use that modified result.Here I've replaced the
toString
onArray.prototype
with a function that sums the Array. Obviously you don't want to do this, but we can show how we will now get a different result.So now you can see that the
ToNumber
conversion of our Array that would previously have resulted inNaN
is now resulting in the sum of the items in the Array.我会尽力而为:
[]===0
当然是 false,因为[]
不完全等于 0。但是,[]== 0
为 true,因为存在隐式强制转换。+
和-[]
之所以有效,是因为加号或减号会将[]
转换为实数。~0
(0 的按位逆)是 -1。因此~[]==-1
有效。其他的只是通过多次减去或加上 -1 来工作。
I'll do my best:
[]===0
is of course false because[]
is not exactly equal to 0. However,[]==0
is true because an implicit cast exists.+
and-[]
work because the plus or minus casts[]
to a real number.~0
(the bitwise inverse of 0) is -1. Thus~[]===-1
works.The others work just by subtracting or adding -1 a bunch of times.
我相信,如果我错了,请纠正我,但是添加到数组(例如,向数组添加值而不是向数组添加值)会将其转换为数字。剩下的就是使用基本的 +、- 运算符(波形符 (~) 是按位 NOT)来修改数字,然后修改方程。
I believe, correct me if I'm wrong, but adding to an array (as in, adding a value to an array rather than adding a value into an array) casts it to a number. The rest is just using basic +, - operators (the tilde (~) is a bitwise NOT) to modify the number and then an equation.