Javascript 为什么 ++[[]][+[]]+[+[]] 返回字符串“10”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7202157/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 01:19:26  来源:igfitidea点击:

Why does ++[[]][+[]]+[+[]] return the string "10"?

javascriptsyntax

提问by JohnJohnGa

This is valid and returns the string "10"in JavaScript (more examples here):

这是有效的并返回"10"JavaScript 中的字符串(更多示例在这里):

console.log(++[[]][+[]]+[+[]])

Why? What is happening here?

为什么?这里发生了什么?

回答by pimvdb

If we split it up, the mess is equal to:

如果我们把它分开,混乱就等于:

++[[]][+[]]
+
[+[]]

In JavaScript, it is true that +[] === 0. +converts something into a number, and in this case it will come down to +""or 0(see specification details below).

在 JavaScript 中,确实如此+[] === 0+将某些内容转换为数字,在这种情况下,它将归结为+""0(请参阅下面的规范详细信息)。

Therefore, we can simplify it (++has precendence over +):

因此,我们可以简化它(++优先于+):

++[[]][0]
+
[0]

Because [[]][0]means: get the first element from [[]], it is true that:

因为[[]][0]意味着:从 中获取第一个元素[[]],所以:

[[]][0]returns the inner array ([]). Due to references it's wrong to say [[]][0] === [], but let's call the inner array Ato avoid the wrong notation.

[[]][0]返回内部数组 ( [])。由于引用,说 是错误的[[]][0] === [],但让我们调用内部数组A以避免错误的表示法。

++before its operand means “increment by one and return the incremented result”. So ++[[]][0]is equivalent to Number(A) + 1(or +A + 1).

++在其操作数之前的意思是“加一并返回增加的结果”。So++[[]][0]等价于Number(A) + 1(或+A + 1)。

Again, we can simplify the mess into something more legible. Let's substitute []back for A:

同样,我们可以将混乱简化为更清晰的内容。让我们[]换回A

(+[] + 1)
+
[0]

Before +[]can coerce the array into the number 0, it needs to be coerced into a string first, which is "", again. Finally, 1is added, which results in 1.

+[]可以将数组强制为 number 之前0,需要先将其强制为字符串,也就是"", 。最后,1相加,结果为1

  • (+[] + 1) === (+"" + 1)
  • (+"" + 1) === (0 + 1)
  • (0 + 1) === 1
  • (+[] + 1) === (+"" + 1)
  • (+"" + 1) === (0 + 1)
  • (0 + 1) === 1

Let's simplify it even more:

让我们进一步简化它:

1
+
[0]

Also, this is true in JavaScript: [0] == "0", because it's joining an array with one element. Joining will concatenate the elements separated by ,. With one element, you can deduce that this logic will result in the first element itself.

此外,这在 JavaScript: 中也是正确的[0] == "0",因为它连接了一个具有一个元素的数组。加入将连接由 分隔的元素,。对于一个元素,您可以推断出此逻辑将生成第一个元素本身。

In this case, +sees two operands: a number and an array. It's now trying to coerce the two into the same type. First, the array is coerced into the string "0", next, the number is coerced into a string ("1"). Number +String ===String.

在这种情况下,+看到两个操作数:一个数字和一个数组。它现在试图将两者强制为同一类型。首先,数组被强制转换为字符串"0",接下来,数字被强制转换为字符串 ( "1")。数字+字符串===字符串

"1" + "0" === "10" // Yay!


Specification details for +[]:

规格详情+[]

This is quite a maze, but to do +[], first it is being converted to a string because that's what +says:

这是一个相当迷宫,但要做到+[]这一点,首先将其转换为字符串,因为这+就是说:

11.4.6 Unary + Operator

The unary + operator converts its operand to Number type.

The production UnaryExpression : + UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.

  2. Return ToNumber(GetValue(expr)).

11.4.6 一元+运算符

一元 + 运算符将其操作数转换为 Number 类型。

产生式 UnaryExpression : + UnaryExpression 的计算方式如下:

  1. 让 expr 是计算 UnaryExpression 的结果。

  2. 返回 ToNumber(GetValue(expr))。

ToNumber()says:

ToNumber()说:

Object

Apply the following steps:

  1. Let primValue be ToPrimitive(input argument, hint String).

  2. Return ToString(primValue).

目的

应用以下步骤:

  1. 令 primValue 为 ToPrimitive(输入参数,提示字符串)。

  2. 返回 ToString(primValue)。

ToPrimitive()says:

ToPrimitive()说:

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.

目的

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

[[DefaultValue]]says:

[[DefaultValue]]说:

8.12.8 [[DefaultValue]] (hint)

When the [[DefaultValue]] internal method of O is called with hint String, the following steps are taken:

  1. Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".

  2. If IsCallable(toString) is true then,

a. Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and an empty argument list.

b. If str is a primitive value, return str.

8.12.8 [[默认值]](提示)

当使用hint String调用O的[[DefaultValue]]内部方法时,采取如下步骤:

  1. 令 toString 是使用参数“toString”调用对象 O 的 [[Get]] 内部方法的结果。

  2. 如果 IsCallable(toString) 为真,则

一种。令 str 为调用 toString 的 [[Call]] 内部方法的结果,其中 O 作为 this 值和一个空参数列表。

湾 如果 str 是原始值,则返回 str。

The .toStringof an array says:

.toString数组的说:

15.4.4.2 Array.prototype.toString ( )

When the toString method is called, the following steps are taken:

  1. Let array be the result of calling ToObject on the this value.

  2. Let func be the result of calling the [[Get]] internal method of array with argument "join".

  3. If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2).

  4. Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list.

15.4.4.2 Array.prototype.toString ( )

当调用 toString 方法时,采取以下步骤:

  1. 让 array 是对 this 值调用 ToObject 的结果。

  2. 让 func 是调用带有参数“join”的数组的 [[Get]] 内部方法的结果。

  3. 如果 IsCallable(func) 为 false,则让 func 成为标准的内置方法 Object.prototype.toString (15.2.4.2)。

  4. 返回调用 func 提供数组的 [[Call]] 内部方法的结果作为 this 值和空参数列表。

So +[]comes down to +"", because [].join() === "".

所以+[]归结为+"",因为[].join() === ""

Again, the +is defined as:

再次+定义为:

11.4.6 Unary + Operator

The unary + operator converts its operand to Number type.

The production UnaryExpression : + UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.

  2. Return ToNumber(GetValue(expr)).

11.4.6 一元+运算符

一元 + 运算符将其操作数转换为 Number 类型。

产生式 UnaryExpression : + UnaryExpression 的计算方式如下:

  1. 让 expr 是计算 UnaryExpression 的结果。

  2. 返回 ToNumber(GetValue(expr))。

ToNumberis defined for ""as:

ToNumber定义为""

The MV of StringNumericLiteral ::: [empty] is 0.

StringNumericLiteral ::: [empty] 的 MV 为 0。

So +"" === 0, and thus +[] === 0.

所以+"" === 0, 因而+[] === 0

回答by Shef

++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1
[+[]] => [0]

Then we have a string concatenation

然后我们有一个字符串连接

1+[0].toString() = 10

回答by Tim Down

The following is adapted from a blog postanswering this question that I posted while this question was still closed. Links are to (an HTML copy of) the ECMAScript 3 spec, still the baseline for JavaScript in today's commonly used web browsers.

以下内容改编自回答此问题的博客文章,我在此问题仍然关闭时发布了该文章。链接指向 ECMAScript 3 规范(的 HTML 副本),该规范仍然是当今常用 Web 浏览器中 JavaScript 的基准。

First, a comment: this kind of expression is never going to show up in any (sane) production environment and is only of any use as an exercise in just how well the reader knows the dirty edges of JavaScript. The general principle that JavaScript operators implicitly convert between types is useful, as are some of the common conversions, but much of the detail in this case is not.

首先,评论:这种表达式永远不会出现在任何(理智的)生产环境中,并且仅用作练习读者对 JavaScript 的肮脏边缘的了解程度。JavaScript 运算符在类型之间隐式转换的一般原则很有用,一些常见的转换也是如此,但在这种情况下的大部分细节都不是。

The expression ++[[]][+[]]+[+[]]may initially look rather imposing and obscure, but is actually relatively easy break down into separate expressions. Below I've simply added parentheses for clarity; I can assure you they change nothing, but if you want to verify that then feel free to read up about the grouping operator. So, the expression can be more clearly written as

该表达式++[[]][+[]]+[+[]]最初可能看起来相当气势和晦涩,但实际上相对容易分解为单独的表达式。为了清楚起见,我在下面简单地添加了括号;我可以向你保证他们不会改变任何东西,但如果你想验证,那么请随意阅读分组操作符。所以,表达式可以更清楚地写成

( ++[[]][+[]] ) + ( [+[]] )

Breaking this down, we can simplify by observing that +[]evaluates to 0. To satisfy yourself why this is true, check out the unary + operatorand follow the slightly tortuous trail which ends up with ToPrimitiveconverting the empty array into an empty string, which is then finally converted to 0by ToNumber. We can now substitute 0for each instance of +[]:

分解这一点,我们可以通过观察+[]评估为来简化0。为了让自己明白为什么这是真的,请查看一元 + 运算符并遵循稍微曲折的路径,最终ToPrimitive将空数组转换为空字符串,然后最终0ToNumber转换为空字符串。我们现在可以替换0的每个实例+[]

( ++[[]][0] ) + [0]

Simpler already. As for ++[[]][0], that's a combination of the prefix increment operator(++), an array literaldefining an array with single element that is itself an empty array ([[]]) and a property accessor([0]) called on the array defined by the array literal.

已经更简单了。至于++[[]][0],它是前缀增量运算符( ++)的组合,一个数组字面量定义了一个具有单个元素的数组,该数组本身就是一个空数组 ( [[]]) 和一个在由数组字面量定义的数组上调用的属性访问器( [0])。

So, we can simplify [[]][0]to just []and we have ++[], right? In fact, this is not the case because evaluating ++[]throws an error, which may initially seem confusing. However, a little thought about the nature of ++makes this clear: it's used to increment a variable (e.g. ++i) or an object property (e.g. ++obj.count). Not only does it evaluate to a value, it also stores that value somewhere. In the case of ++[], it has nowhere to put the new value (whatever it may be) because there is no reference to an object property or variable to update. In spec terms, this is covered by the internal PutValueoperation, which is called by the prefix increment operator.

所以,我们可以简化[[]][0]为 just [],我们有++[],对吧?事实上,情况并非如此,因为评估++[]会引发错误,这最初可能会令人困惑。但是,稍微考虑一下 的性质就++可以清楚地说明这一点:它用于增加变量(例如++i)或对象属性(例如++obj.count)。它不仅计算出一个值,它还将该值存储在某处。在 的情况下++[],它无处放置新值(无论它是什么),因为没有对要更新的对象属性或变量的引用。在规范方面,这由内部PutValue操作涵盖,该操作由前缀增量运算符调用。

So then, what does ++[[]][0]do? Well, by similar logic as +[], the inner array is converted to 0and this value is incremented by 1to give us a final value of 1. The value of property 0in the outer array is updated to 1and the whole expression evaluates to 1.

那么,有什么作用++[[]][0]呢?好吧,通过与 类似的逻辑+[],内部数组被转换为0并且这个值增加1以给我们一个最终值10外部数组中的 property 值更新为1并且整个表达式的计算结果为1

This leaves us with

这给我们留下了

1 + [0]

... which is a simple use of the addition operator. Both operands are first converted to primitivesand if either primitive value is a string, string concatenation is performed, otherwise numeric addition is performed. [0]converts to "0", so string concatenation is used, producing "10".

...这是加法运算符的简单用法。两个操作数首先被转换为原始值,如果其中一个原始值是字符串,则执行字符串连接,否则执行数字加法。[0]转换为"0",因此使用字符串连接,产生"10".

As a final aside, something that may not be immediately apparent is that overriding either one of the toString()or valueOf()methods of Array.prototypewill change the result of the expression, because both are checked and used if present when converting an object into a primitive value. For example, the following

最后,可能不是很明显的事情是,覆盖toString()valueOf()方法中的任何一个Array.prototype都会改变表达式的结果,因为在将对象转换为原始值时,如果存在,则会检查和使用这两个方法。例如,以下

Array.prototype.toString = function() {
  return "foo";
};
++[[]][+[]]+[+[]]

... produces "NaNfoo". Why this happens is left as an exercise for the reader...

... 产生"NaNfoo". 为什么会发生这种情况留给读者作为练习......

回答by renatoluna

Let's make it simple:

让我们简单点:

++[[]][+[]]+[+[]] = "10"

var a = [[]][+[]];
var b = [+[]];

// so a == [] and b == [0]

++a;

// then a == 1 and b is still that array [0]
// when you sum the var a and an array, it will sum b as a string just like that:

1 + "0" = "10"

回答by Vlad Shlosberg

This one evaluates to the same but a bit smaller

这个评估结果相同但小一点

+!![]+''+(+[])
  • [] - is an array is converted that is converted to 0 when you add or subtract from it, so hence +[] = 0
  • ![] - evaluates to false, so hence !![] evaluates to true
  • +!![] - converts the true to a numeric value that evaluates to true, so in this case 1
  • +'' - appends an empty string to the expression causing the number to be converted to string
  • +[] - evaluates to 0
  • [] - 是一个数组被转换,当你添加或减去它时转换为 0,因此 +[] = 0
  • ![] - 评估为 false,因此 !![] 评估为 true
  • +!![] - 将 true 转换为计算结果为 true 的数值,因此在这种情况下为 1
  • +'' - 将一个空字符串附加到表达式中,导致数字被转换为字符串
  • +[] - 计算结果为 0

so is evaluates to

所以评估为

+(true) + '' + (0)
1 + '' + 0
"10"

So now you got that, try this one:

所以现在你明白了,试试这个:

_=$=+[],++_+''+$

回答by Eskat0n

+[] evaluates to 0 [...] then summing (+ operation) it with anything converts array content to its string representation consisting of elements joined with comma.

+[] 评估为 0 [...] 然后将它与任何东西相加(+ 运算)将数组内容转换为其字符串表示形式,该字符串表示由用逗号连接的元素组成。

Anything other like taking index of array (have grater priority than + operation) is ordinal and is nothing interesting.

任何其他像获取数组索引(具有比 + 操作更高的优先级)的东西都是有序的,没什么有趣的。

回答by Arman McHitarian

Perhaps the shortest possible ways to evaluate an expression into "10" without digits are:

也许将表达式计算为没有数字的“10”的最短方法是:

+!+[] + [+[]]// "10"

+!+[] + [+[]]// "10"

-~[] + [+[]]// "10"

-~[] + [+[]]// "10"

//========== Explanation ==========\\

//========== 说明 ============\\

+!+[]: +[]Converts to 0. !0converts to true. +trueconverts to 1. -~[]= -(-1)which is 1

+!+[]:+[]转换为 0.!0转换为true. +true转换为 1。 -~[]=-(-1)即 1

[+[]]: +[]Converts to 0. [0]is an array with a single element 0.

[+[]]:+[]转换为 0.[0]是单个元素为 0的数组。

Then JS evaluates the 1 + [0], thus Number + Arrayexpression. Then the ECMA specification works: +operator converts both operands to a string by calling the toString()/valueOf()functions from the base Objectprototype. It operates as an additive function if both operands of an expression are numbers only. The trick is that arrays easily convert their elements into a concatenated string representation.

然后 JS 计算1 + [0], 因此Number + Array表达式。然后 ECMA 规范起作用:+运算符通过toString()/valueOf()从基本Object原型调用函数将两个操作数转换为字符串。如果表达式的两个操作数都只是数字,则它作为加法函数运行。诀窍是数组可以轻松地将它们的元素转换为连接的字符串表示形式。

Some examples:

一些例子:

1 + {} //    "1[object Object]"
1 + [] //    "1"
1 + new Date() //    "1Wed Jun 19 2013 12:13:25 GMT+0400 (Caucasus Standard Time)"

There's a nice exception that two Objectsaddition results in NaN:

有一个很好的例外,两个Objects加法导致NaN

[] + []   //    ""
[1] + [2] //    "12"
{} + {}   //    NaN
{a:1} + {b:2}     //    NaN
[1, {}] + [2, {}] //    "1,[object Object]2,[object Object]"

回答by Alireza

Step by steps of that, +turn value to a number and if you add to an empty array +[]...as it's empty and is equal to 0, it will

一步一步地,+将 value 转换为一个数字,如果你添加到一个空数组+[]......因为它是空的并且等于0,它将

So from there, now look into your code, it's ++[[]][+[]]+[+[]]...

所以从那里开始,现在看看你的代码,它是++[[]][+[]]+[+[]]......

And there is plus between them ++[[]][+[]]+ [+[]]

他们之间还有加号++[[]][+[]]+[+[]]

So these [+[]]will return [0]as they have an empty array which gets converted to 0inside the other array...

所以这些[+[]]将返回,[0]因为它们有一个空数组,该数组被转换为0另一个数组......

So as imagine, the first value is a 2-dimensionalarray with one array inside... so [[]][+[]]will be equal to [[]][0]which will return []...

所以想象一下,第一个值是一个二维数组,里面有一个数组......所以[[]][+[]]将等于[[]][0]which 将返回[]......

And at the end ++convert it and increase it to 1...

最后++将其转换并增加到1......

So you can imagine, 1+ "0"will be "10"...

所以你可以想象,1+"0"将是"10"......

Why does return the string “10”?

为什么返回字符串“10”?

回答by Praveen Vedanth

  1. Unary plus given string converts to number
  2. Increment operator given string converts and increments by 1
  3. [] == ''. Empty String
  4. +'' or +[] evaluates 0.

    ++[[]][+[]]+[+[]] = 10 
    ++[''][0] + [0] : First part is gives zeroth element of the array which is empty string 
    1+0 
    10
    
  1. 一元加给定字符串转换为数字
  2. 给定字符串的递增运算符转换并递增 1
  3. [] == ''。空字符串
  4. +'' 或 +[] 求值为 0。

    ++[[]][+[]]+[+[]] = 10 
    ++[''][0] + [0] : First part is gives zeroth element of the array which is empty string 
    1+0 
    10