Tomas Forsman

Posted on

# Why (! + [] + [] + ![]).length is 9

Edit: At the bottom I've added what I've figured out since I wrote this.

Today I sat down and figured out why you get this result in JavaScript

``````(! + [] + [] + ![]).length
> 9
``````

So I sat down with the js console and tried to figure things out. There were a lot of this going on:

``````(!"")
>true

(![])
>false

(!+[])
>true

(!+[]+[])
>"true"

(+[]+"2")
>"02"

([]+"2")
>"2"
``````

What I have come up with, and I might be totally off on some of these so please correct anything that doesn't look right, is the following.

• JavaScript does operations from right to left.
• The + operand first tries to add the left to the right, if that isn't possible it tries to convert the operand on the right to a number and if it can't do that it converts it to a string. If there is something to the left of the + it adds them together, and if it can't it sticks around. If there is nothing to the left it goes away.
• The ! operand converts the operand to the right to a boolean and then reverts it. Only the following values are the same as false as booleans:
``````false
0
""
null
NaN
undefined
``````

All other values is not false and thus true.

So now it goes something like this:

``````// We start with
(! + [] + [] + ![]).length  // Remember that we are going from right to left starting
// with the operation before doing -length
![] === false               // ! converts the content of [] to true, since it's not part of
// the false group above, and then reverts it.
+ === +                     // the + is lonely so far with no operand to the right but sticks
// around since it has something on the left.
[]+[] === ""                // The contents of [] can't be added or converted to a number so
// the right operand becomes a string. There's still something to
// the left so the + stays.
!+[] === true               // This the same as !+0 since +[] is 0

// Now we got:
("false" + "" + false).length
""+false === "false"        // + adds "" to false. It then sticks around.
"true" + "" === "true"      // The + stays after adding "true" to ""

// ---
("true"++"false")
+"false" ==== "false"       // + has nothing but an operand to the left so it goes away.
true + "" === "true"        // + adds them together and stays

// ---
("true"+"false")
"true" + "false" === "truefalse" // + still stays

// ---
(+"truefalse")
+"truefalse" === "truefalse"     // + has nothing to do after this so it goes away

// ---
("truefalse")               // The operation is done so now we are left with what's outside.

"truefalse".length === 9

``````

Yes, I did go through every step, even those that seems pointless. I'm not at all sure this is how it works but it is what seems to happen to me.

Thoughts?

Edit:
After comments and looking at the documentation this is now how I figure things going.
((!(+[]))+[]+(![]))
Unary operators are going right to left thus !+[] becomes +[] -> !0 === true.

tPenguinLTG

JavaScript does operations from right to left.

In some cases it does, but not in this case. The reason you see behaviour that may appear to be right-to-left evaluation is because of operator precedence, where the unary `!` has a higher precedence than the binary `+`.

`+` actually evaluates from left to right, so more verbosely parenthesized, it looks like this:

``````(((!(+[])) + []) + (![])).length
``````

Evaluating this parenthesized form step-by-step, we get this:

``````/*  1. */ (((!(+[])) + []) + (![])).length  // parethesized form.
/*  2. */ (((!0) + []) + (![])).length      // `+[]` is evaluated to `0`.
/*  3. */ (((!false) + []) + (![])).length  // `0` is coerced to the boolean `false`.
/*  4. */ ((true + []) + (![])).length      // `!false` is evaluated to `true`.
/*  5. */ (("true" + "") + (![])).length    // `[]` is coerced as a primitive to the string `""`, which means `true` is also coerced to a string.
/*  6. */ ("true" + (![])).length           // `"true" + ""` is string concatenation, which evaluates to `"true"`.
/*  7. */ ("true" + (!true)).length         // `[]` is coerced to the boolean `true`.
/*  8. */ ("true" + false).length           // `!true` evaluates to `false`.
/*  9. */ ("true" + "false").length         // `false` is coerced to a string because `"true"` is a string.
/* 10. */ "truefalse".length                // `"true" + "false"` is evaluated as string concatenation to `"truefalse".
/* 11. */ 9                                 // the length of `"truefalse"` is `9`.
``````

Tomas Forsman

The first + is unary, right?

tPenguinLTG

Indeed it is.

Eugene Karataev

If I'm not sure what's going on with the JS code, I use ASTexplorer to look at the code with the compiler's eyes. It converts a code string into the tree of instructions to be executed by the compiler step by step.
But sometimes text representation of a tree is not expressive enough, so I built a little tool which visualizes an AST tree.
For `(! + [] + [] + ![]).length` AST in graph form looks like this:

In runtime calculations starts from the bottom left and flow to the top.

Tomas Forsman

love this!

Jacob Paris • Edited
``````(({})[[]]+[]).length
``````

This is also equal to 9 but for a very different reason

tyskie
``````(-1/0+[]).length
``````

This one too but for yet another reason

Ben Sinclair
``````(({})[[]]+[])[1]+(({})[[]]+[])[5]+(({})[[]]+[])[1]+(({})[[]]+[])[3]
``````

Standing on the shoulders of giants.

Jacob Paris

You can stand on your own shoulders this was perfect

Kassem

Interesting breakdown. I might have missed something but I think "truefalls" should be "truefalse".

Tomas Forsman

Indeed it should =D That's dyslexia for ya.

Ain't that the truef.

Sagar Bhattacharya • Edited

It is a great observation , typecasting in JS is weird. This is the reason I love this platform.

Alex Luong

AWESOME INTERVIEW QUESTION!!!

aerosboss

jajaja many brains will explode

nabbisen

Totally greatly interesting.
Thank you for your great post.
The behaviors seem a bit strange and are beautiful π

WhistlerIAM

Hi.
This is very well documented in the Boolean coercion abstract operation by ECMAScript language.
So, there are two operations that you may check out.

1. ToBoolean and ToString.