JavaScript 中的 ~[] 结构如何工作?

发布于 2024-12-17 19:17:59 字数 392 浏览 2 评论 0原文

我遇到了一段无法解释的有效 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一袭白衣梦中忆 2024-12-24 19:17:59

[] 是一个空数组对象,所以:

+[]:强制空数组为正整数,又名 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...

涫野音 2024-12-24 19:17:59

当您对任何内容使用 +- 运算符时,它会对其调用 NumberNumber([]) 返回 0,因此您可以获得前两个答案。

~ 运算符是按位 NOT。基本上,它反转数字中的所有位,将 0 更改为 -1。有关按位运算符的更多信息,请此处

其余的只是这些情况的组合。你几乎可以将这些东西结合起来得到你想要的任何数字。

When you use the + or - operator on anything, it calls Number on it. Number([]) returns 0, so you get your first two answers.

The ~ operator is bitwise NOT. Basically it inverses all the bits in a number, which changes 0 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.

欲拥i 2024-12-24 19:17:59

我不会只是重述您在问题中演示的结果,而是尝试描述您为什么会得到该结果。

解释

仅以第一个示例为例(因为其余示例也会做类似的事情),我们可以按照规范来看看会发生什么。

11.4.6 Unary + Operator 中,我们可以看到一个 ToNumber 发生转换。

返回ToNumber(GetValue(expr))。

9.3 ToNumber 中我们看到,如果给定一个对象(比如你的数组),一个 发生 ToPrimitive 转换,然后再次尝试 ToNumber

对象

应用以下步骤:

  1. 设 primValue 为 ToPrimitive(输入参数,提示编号)。
  2. 返回ToNumber(primValue)。

9.1 到 Primitive,如果 ToPrimitive 得到一个 Object,我们可以看到它的 [[DefaultValue]] 已被获取:

对象

返回对象的默认值。对象的默认值是通过调用对象的 [[DefaultValue]] 内部方法并传递可选提示 PreferredType 来检索的。本规范为 8.12.8 中的所有本机 ECMAScript 对象定义了 [[DefaultValue]] 内部方法的行为。

8.12.8 [[DefaultValue]](提示)开始,最终会发生的是toString() 将在数组上调用并返回。如上所述,该字符串被发送到递归 ToNumber

那么当对字符串进行 ToNumber 转换时会发生什么?嗯,它在9.3.1 ToNumber Applied to the String Type中进行了描述,并且有点长。更简单的是直接进行转换,然后看看会发生什么:

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

一些证明

为了进一步证明此 toString() 转换发生在 ToNumber 转换之前,我们实际上可以修改 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 转换现在会导致数组中各项的总和。

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.

Return ToNumber(GetValue(expr)).

From 9.3 ToNumber we see that if given an Object (like your Array), a ToPrimitive conversion takes place followed by another attempt at ToNumber.

Object

Apply the following steps:

  1. Let primValue be ToPrimitive(input argument, hint Number).
  2. Return ToNumber(primValue).

From 9.1 To Primitive, if ToPrimitive gets an Object, we can see that its [[DefaultValue]] is fetched:

Object

Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.

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 recursive ToNumber 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:

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

So the question is, what string do we get back from our Array. Again, this is easy to simply test.

[].toString();  // result is "" (empty string)

Since the result is an empty string, and a ToNumber conversion of an empty string is 0 as shown above, that would mean we are comparing 0 === 0.

It would be the same as if we did:

Number( [].toString() ) === 0; // true

Or to draw it out a bit more:

var x = [];
x = x.toString();  // ""
x = Number( x );   // 0
x === 0;  // true

More toString results.

To show more toString conversions of Arrays, consider the following:

[1].toString();            // "1"
[1,2,3].toString();        // "1,2,3"
["a",1,"b",2].toString();  // "a,1,b,2"

So to do a ToNumber conversion on the above Arrays, the first would give us a number, and the last two would result in NaN.

Number([1]);            // 1
Number([1,2,3]);        // NaN
Number(["a",1,"b",2]);  // NaN

Some proof

To provide further proof that this toString() conversion happens before the ToNumber conversion, we can actually modify Array.prototype.toString to provide a different result, and any ToNumber conversions will use that modified result.

Array.prototype.toString = function() {
    var n = 0;
    for( var i = 0; i < this.length; i++ ) {
        n += this[i];
    }
    return n;
};

Here I've replaced the toString on Array.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.

Number([1,2,3]);   // 6
+[1,2,3];          // 6

So now you can see that the ToNumber conversion of our Array that would previously have resulted in NaN is now resulting in the sum of the items in the Array.

初见你 2024-12-24 19:17:59

我会尽力而为:

[]===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.

桃气十足 2024-12-24 19:17:59

我相信,如果我错了,请纠正我,但是添加到数组(例如,向数组添加值而不是向数组添加值)会将其转换为数字。剩下的就是使用基本的 +、- 运算符(波形符 (~) 是按位 NOT)来修改数字,然后修改方程。

So [] == array ([]);
[] + 1 == number (0);
+[]===0 (true)

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.

So [] == array ([]);
[] + 1 == number (0);
+[]===0 (true)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文