By JohnJohnGa


2011-08-26 08:46:14 8 Comments

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

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

Why? What is happening here?

9 comments

@pimvdb 2011-08-26 08:56:54

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).

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

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

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

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

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

Again, we can simplify the mess into something more legible. Let's substitute [] back for 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, 1 is added, which results in 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.

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.

"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)).

ToNumber() says:

Object

Apply the following steps:

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

  2. Return ToString(primValue).

ToPrimitive() says:

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]] says:

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.

The .toString of an array says:

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.

So +[] comes down to +"", because [].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)).

ToNumber is defined for "" as:

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

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

@Lie Ryan 2011-08-26 10:37:21

how do you go from ++[[]][0] to [] + 1?

@pimvdb 2011-08-26 11:25:46

@Lie Ryan: [[]][0] is that nested []. ++ increments with one, so it returns [] + 1.

@jprete 2011-08-26 13:48:30

Suggestion: make the "++[[]][0] to [] + 1" transformation explicit in the post. It makes the whole thing a lot more understandable for those of us who don't actually know JavaScript!

@harper 2011-08-26 13:53:08

I know = for assignment and == for comparision. What is ===?

@pimvdb 2011-08-26 14:04:08

@harper: It's the strict equality checker, i.e. it only returns true if both the value and type are the same. 0 == "" returns true (same after type conversion), but 0 === "" is false (not same types).

@Tim Down 2011-09-09 14:10:13

Part of this isn't correct. The expression boils down to 1 + [0], not "1" + [0], because the prefix (++) operator always returns a number. See bclary.com/2004/11/07/#a-11.4.4

@pimvdb 2011-09-09 14:42:59

@Tim Down: You're completely correct. I'm trying to correct this, but when trying to do so I found something else. I'm not sure how this is possible. ++[[]][0] returns indeed 1, but ++[] throws an error. This is remarkable because it looks like ++[[]][0] does boil down to ++[]. Do you perhaps have any idea why ++[] throws an error whereas ++[[]][0] does not?

@Tim Down 2011-09-09 15:36:48

@pimvdb: I'm pretty sure the problem is in the PutValue call (in ES3 terminology, 8.7.2) in the prefix operation. PutValue requires a Reference whereas [] as an expression on its own does not produce a Reference. An expression containing a variable reference (say we'd previously defined var a = [] then ++a works) or property access of an object (such as [[]][0]) produces a Reference. In simpler terms, the prefix operator not only produces a value, it also needs somewhere to put that value.

@Tim Down 2011-09-09 15:50:59

@pimvdb: So after executing var a = []; ++a, a is 1. After executing ++[[]][0], the array created by the [[]] expression is now contains just the number 1 at index 0. ++ requires a Reference to do this.

@Dan Beam 2011-12-29 03:03:25

nit: An instanceof Array (like []) will never === an Array other than itself, as the Strict Comparison Operator simply compares lref to rref (i.e. the memory locations of each instance). I wouldn't recommend even implying this. You might also note in your answer that JS' Unary + Operator has precedence over the result of any arithmetic expression result or string concatenation (depending on context) with ++ or + which is why +[] gets evaluated first.

@pimvdb 2011-12-29 11:45:59

@Dan Beam: Very true, thanks for your feedback. (As a side note, the abstract equality operator also checks for references; I just always use the strict equality operator to avoid quirks.)

@user4642212 2019-08-05 09:43:32

++[[]][0] === +(A + 1) — That’s wrong. Instead: ++[[]][0] === +A + 1. A is coerced to a string, then to a number, then 1 is added. The addition doesn’t come before the number coercion, otherwise it would be concatenation. Try Array.prototype.toString = function toString(){ if(this.length === 0){ return "1"; } }; ++[[]][0];. You’ll get 2, not 11 (which would be the case with +([] + 1)). I’m editing this answer to fix this.

@Alireza 2019-01-19 00:32:25

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

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 0 inside the other array...

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

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

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

Why does return the string “10”?

@renatoluna 2011-12-30 15:41:20

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"

@Vlad Shlosberg 2011-12-28 23:13:34

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:

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

@Vlad Shlosberg 2011-12-30 06:38:56

Well no it still evaluates to "10". However this is doing it in a different way. Try evaluating this in a javascript inspector like chrome or something.

@LeagueOfJava 2018-04-28 04:33:26

_=$=+[],++_+''+$ -> _=$=0,++_+''+$ -> _=0,$=0,++_+''+$ -> ++0+''+0 -> 1+''+0 -> '10' // Yei :v

@Arman McHitarian 2013-06-19 08:19:14

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]"

@Praveen Vedanth 2011-12-30 08:10:09

  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
    

@PointedEars 2012-01-12 04:41:17

The answer is confused/confusing, IOW wrong. [] is not equivalent to "". First the element is extracted, then converted by ++.

@Tim Down 2011-09-14 13:54:39

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...

@Eskat0n 2011-08-26 08:58:44

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

@Shef 2011-08-26 08:58:23

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

Then we have a string concatenation

1+[0].toString() = 10

@Mateen Ulhaq 2018-12-19 02:46:52

Wouldn't it be clearer to write === rather than =>?

Related Questions

Sponsored Content

37 Answered Questions

[SOLVED] How do I return the response from an asynchronous call?

48 Answered Questions

27 Answered Questions

[SOLVED] What does "use strict" do in JavaScript, and what is the reasoning behind it?

43 Answered Questions

[SOLVED] When to use double or single quotes in JavaScript?

6 Answered Questions

[SOLVED] Why does Google prepend while(1); to their JSON responses?

4 Answered Questions

38 Answered Questions

[SOLVED] var functionName = function() {} vs function functionName() {}

19 Answered Questions

[SOLVED] Is it possible to apply CSS to half of a character?

  • 2014-05-09 16:16:57
  • Mathew MacLean
  • 237542 View
  • 2746 Score
  • 19 Answer
  • Tags:   javascript html css

14 Answered Questions

[SOLVED] How does data binding work in AngularJS?

Sponsored Content