7

I have recently seen an expression from a source, which looks something like below -

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

Entering this into the Chrome (Windows 7, Version 27.0.1453.94 m) console shows a result of "10".

Can someone explain what's happening here?

JSFiddle.

MD Sayem Ahmed
  • 28,628
  • 27
  • 111
  • 178

3 Answers3

4

JavaScript is fairly flexible about converting between data types. The first thing to notice is that +[] evaluates to 0.* That lets us rewrite the expression as:

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

The next thing to notice is that ++[[]][0] is the preincrement operator applied to the first element of [[]]. Normally you can't apply ++ to an array, but JavaScript kindly converts the first element to 0, so the result is that ++[[]][0] evaluates to 1 (the first element of [[]] having now been incremented). It is kind of like this:

var a = [[]];
var b = ++a[0];
// now a will be [1] and b will be 1

That leaves us with:

1 + [0]

JavaScript now converts the int and the array to strings (since [0] is not a numeric value) and concatenates them together. Done!

* My understanding of how +[] becomes 0 is that it is a two-step process: first, [] is converted to a string primitive, which is the empty string. The empty string then converts to a number, which is zero. Via the same route, [1] evaluates to '1' and then to 1, [2] evaluates to 2, etc. However, [1, 2] evaluates to '1,2' which evaluates to NaN. (The last because the decimal point separator is ., not ,. I don't know what would happen if my locale were different.)

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • I pretty much assumed this far. Just wondering about converting `[[]][0]` to `0` part. Which conversion rule is followed during this process? – MD Sayem Ahmed May 31 '13 at 06:56
  • 1
    @SayemAhmed - While the `++` cannot be applied to an array, it can be applied to an array element. The first element of `[[]]` is `[]`; trying to apply `++` to that triggers JS to convert `[]` to 0 (just like it did with `+[]`). – Ted Hopp May 31 '13 at 07:00
  • Okay, I see your point. I am just finding the behavior of the ++ operator a little difficult to understand. You cannot apply it to array, that I get. But when you apply it to an array element and if the element is itself an array, then it gets converted to a primitive? Does the ECMA specification list this behavior somewhere? – MD Sayem Ahmed May 31 '13 at 08:48
  • 1
    @SayemAhmed - §11.4.4 says that `++Expr` starts (after some error checking) by evaluating `ToNumber(GetValue(Expr))`. §9.3 specifies that `ToNumber` for an object argument starts by evaluating `ToPrimitive(value, Number)`. That, in turn, (per §9.1) calls the object's `[[DefaultValue]]` internal method. §8.12.8 describes how `[[DefaultValue]]` works for an object when the hint type is Number. The process specified there is essentially what I described: convert to a string (after first unsuccessfully trying to covert to a primitive using `valueOf()`) That's then parsed as a number (per §9.3). – Ted Hopp May 31 '13 at 14:44
2

This expression stringifies valid Javascript constructs that yelds NaN, numbers, boolean undefined etc.

e.g.

+[] -> 0  //The unary plus operator is applied to the result of toString applied to an empty array (which is an empty string)

!+[] -> true

You can have a look also at this question, and at the no alnum cheat sheets.

Community
  • 1
  • 1
mamoo
  • 8,156
  • 2
  • 28
  • 38
  • I figured out that part. I reduced the expression down to `++[[]][0]+[0]`, just can't figure out how the `1` is coming up here...... – MD Sayem Ahmed May 31 '13 at 06:47
  • Okay, I see the cheat sheet has listed `++[[]][+[]]` as equivalent to `1`, but doesn't give any explanation........ – MD Sayem Ahmed May 31 '13 at 06:52
2

+[] is a number conversion from array to number which is 0.

and +[0] is also 0.

So the final result can be deduced to (++0) + [0] which is 1+[0].

And for a number adding an array. They are converted to string so the result is actually '10'.

You can log typeof(++[[]][+[]]+[+[]]) to verify.

Chris Li
  • 3,715
  • 3
  • 29
  • 31