Why is this expression evaluated to "a" in JavaScript? [duplicate]
Asked Answered
F

5

7

I got hold of some obfuscated JavaScript code. I tried to understand it, and doing this, I typed pieces of it in the console. I can't understand why

> ((!!+[]+"")[+!![]])
< "a"

Why is ((!!+[]+"")[+!![]]) equal to "a" in JavaScript? Is there some other code snippets to get others letters?

I guess it's something to do with automatic casting.

Footmark answered 28/5, 2017 at 15:32 Comment(3)
This whole thing can be simplified to ("false"[1]) . Now you know why the result is a.Vinic
a is the second letter of false. Clever ^^Footmark
@Vinic why (!!+[]+"") equal to "false" and why +!![] equal to 1Laryssa
A
8
( ( !!+[] + "" ) [ +!![] ] )
( (  !!0  + "" ) [ +true ] )
( ( false + "" ) [ +true ] )
( (   "false"  ) [   1   ] )
(         "false"[1]       )
(            "a"           ) 

Is there some other code snippets to get others letters ?

You can play with the same concept to get all the letters from "true", "false", "undefined", "NaN"...

Advisory answered 28/5, 2017 at 15:40 Comment(4)
That's the right answer.Tobolsk
Why does +[] equal 0? Guess it converts empty array to number, so, why not 0... but that deserves a small line I think... and better than my guess if possible :)Kayak
@HuguesMoreau the unary plus operation + is parsing [] to a number typeAdvisory
and why? destroyallsoftware.com/talks/watAdvisory
U
4

You should work on operator precedence and type castings in JavaScript:

!!+[] // Is falsey. this is same for !!+0 or !!+""
false + "" // Is "false". as 5+"" is "5".

![] // Is falsey.
!false // Is true
+true //  Is equal to 1. +[] = 0, +false = 0

And at least,

"false"[1] // Is "a"
Underbrush answered 28/5, 2017 at 15:40 Comment(2)
Do you have a good reference for operator precedence in JavaScript?Animated
mozilla documentation is good enough i believe. i always refer there. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…Underbrush
T
4

Let's use the console to get our answer assuming we don't know what any of this means, typing

[] + "" in the console outputs ""

Just putting (!!+[]) returns the Boolean false. If you append the Boolean false to "", you get the String false due to type coercion.

As expected, typing (!!+[]+"") outputs "false" to the console.

Moving on, in JavaScript, you can think of strings like an array of characters and you can access their character using the array notation.

So, in ((!!+[]+"")[+!![]]), you can remove the outermost brackets to make it seem simpler. Now we have (!!+[]+"")[+!![]] in which the first part in () returns the String "false", and the next part in [] accesses a character of the String "false". You can now bet that +!![] somehow returns 1 since "false"[1] equals "a".

Now let's find out how +!![] equals 1:

[] is an empty array which you can think of as 0 which would be true in JavaScript (because "in JavaScript anything 'real' is true"), so ![] is false and !![] is true.

Now we are left with +true which is just shorthand for convert true to a number which would be 1. Now you can see how +!![] evaluates to 1 and you understand (hopefully) how that obfuscated piece of code works!

Teasley answered 28/5, 2017 at 15:42 Comment(0)
A
3

The key to understand this is to know that JavaScript does implicit type conversions to evalute expressions it sees. In other words, while you might not know what it means to add a number to a string, JavaScript will make a guess rather than emitting an error. It is contrary to what you'd get in C++ which gives an explicit error in this case.

For example, +x always evaluates to a number, no matter what is type x actually is. Same thing for !x. Therefore, for your expression:

// A: !!+[]+"" which is evaluated like !(!(+[]))+""
+[]       === 0
!0        === true
!true     === false
false+''  === 'false'

// B: +!![] which is evaluated like +(!(![]))
![]       === false
!false    === true
+true     === 1

we get A[B] which is simply 'false'[1] === 'a'.

You can learn more about implicit type conversions and operator precedence at MDN.

Implicit type conversions is the reason why experienced JavaScript programmers prefer to use === rather than == when comparing values.

Amalgam answered 28/5, 2017 at 15:55 Comment(0)
V
2

Here's detailed step by step process of what is happening:

( !! +[] + "" ) [ +!![] ]
//   ^^^ 

+[] Unary plus on array literal operates, which is equivalent Number([]) which results in 0. See this to why this evaluates to 0.

( !! 0 + "" ) [ +!![] ]
//^^^^

!!0 is equivalent to !!Boolean(0)) which evaluates to false since 0 is falsy value.

( false + "" ) [ +!![] ]
//^^^^^^^^^^^

false+"" is simple string concatenation therefore evaluates to "false"

"false" [ +!![] ]
//         ^^^^ 

!![] is equivalent to !!Boolean([]) and since Boolean conversion of objects returns always true. This evaluates to true.

"false" [ +true ]
//        ^^^^^

+true is equivalent to Number(true) which evaluates to 1.

"false" [ 1 ]

which is finally a.

The keypoint here is Javascript does implicit type conversion or Type Coercion while evaluating the expressions. To learn more about Type Coercion I suggest this excellent resource written by Dr. Axel Rauschmayer

Type Coercion

Vinic answered 28/5, 2017 at 16:7 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.