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

Tomas Forsman on July 14, 2019

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 ... [Read Full]
markdown guide
 

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

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:
ast
In runtime calculations starts from the bottom left and flow to the top.

 
 
(({})[[]]+[]).length

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

 
(-1/0+[]).length

This one too but for yet another reason

 
(({})[[]]+[])[1]+(({})[[]]+[])[5]+(({})[[]]+[])[1]+(({})[[]]+[])[3]

Standing on the shoulders of giants.

You can stand on your own shoulders this was perfect

 

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

 
 

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

 
 

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.
 
 
 

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

code of conduct - report abuse