Cover image for Why (! + [] + [] + ![]).length is 9

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

tomasforsman profile image Tomas Forsman ・2 min read

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:







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:

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

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

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

// ---
+"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.


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.


Editor guide
tpenguinltg profile image

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`.
tomasforsman profile image
Tomas Forsman Author

The first + is unary, right?

tpenguinltg profile image

Indeed it is.

karataev profile image
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.

tomasforsman profile image
jacobmparis profile image
Jacob Paris

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

tyskie profile image

This one too but for yet another reason

moopet profile image
Ben Sinclair

Standing on the shoulders of giants.

Thread Thread
jacobmparis profile image
Jacob Paris

You can stand on your own shoulders this was perfect

kassem profile image

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

tomasforsman profile image
Tomas Forsman Author

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

tadman profile image
Scott Tadman

Ain't that the truef.

sagarb3 profile image
Sagar Bhattacharya

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

alexluong profile image
Alex Luong


aerosboss profile image

jajaja many brains will explode

nabbisen profile image
Heddi Nabbisen

Totally greatly interesting.
Thank you for your great post.
The behaviors seem a bit strange and are beautiful 😆

vocab_king profile image

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.
acido_binario profile image
🍝 sadder sCrypt Kiddie 𖤐🕷️

Is this ease of programming?

copy_pasta_chef profile image

Does this have anything to do with the esoteric version of JS? en.m.wikipedia.org/wiki/JSFuck