Why does ++[[]][+[]]+[+[]] return the string “10”?

2018-12-31 08:46发布

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

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

Why? What is happening here?

8条回答
ら面具成の殇う
2楼-- · 2018-12-31 09:24

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

so is evaluates to

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

So now you got that, try this one:

_=$=+[],++_+''+$
查看更多
孤独总比滥情好
3楼-- · 2018-12-31 09:37
++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1
[+[]] => [0]

Then we have a string concatenation

1+[0].toString() = 10
查看更多
浮光初槿花落
4楼-- · 2018-12-31 09:39

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

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

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

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

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

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

Then JS evaluates the 1 + [0], thus Number + Array expression. Then the ECMA specification works: + operator converts both operands to a string by calling the toString()/valueOf() functions from the base Object prototype. 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.

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 Objects addition results in NaN:

[] + []   //    ""
[1] + [2] //    "12"
{} + {}   //    NaN
{a:1} + {b:2}     //    NaN
[1, {}] + [2, {}] //    "1,[object Object]2,[object Object]"
查看更多
何处买醉
5楼-- · 2018-12-31 09:40

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

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

查看更多
残风、尘缘若梦
6楼-- · 2018-12-31 09:44

The following is adapted from a blog post answering 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.

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.

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 + operator and follow the slightly tortuous trail which ends up with ToPrimitive converting the empty array into an empty string, which is then finally converted to 0 by ToNumber. We can now substitute 0 for each instance of +[]:

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

Simpler already. As for ++[[]][0], that’s a combination of the prefix increment operator (++), an array literal defining 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.

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 PutValue operation, which is called by the prefix increment operator.

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

This leaves us with

1 + [0]

... which is a simple use of the addition operator. Both operands are first converted to primitives and 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".

As a final aside, something that may not be immediately apparent is that overriding either one of the toString() or valueOf() methods of Array.prototype will 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

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

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

查看更多
伤终究还是伤i
7楼-- · 2018-12-31 09:44

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"
查看更多
登录 后发表回答