0

I was reading these slides and I found the following javascript line:

 ({} + [])[!![] + !![] + !![]] + (![] + [])[!![] + !![] + !![]]

If you execute this line at the console, it will return "js". Altering the code makes the line return different letters. I could almost return my name(missing "n"):

({} + [])[!![] + !![] + !![]] + (![] + {})[!![] + !![] + !![] + !![]] + (![] + {})[![] + !![] ]

Why this happens? How this works? The slides didn't give much information about it.

Jean Lourenço
  • 675
  • 6
  • 17

2 Answers2

2
  • {} + [] : When the + has operands other than numbers, it calls toString on both operands and concatenates their values. {}.toString() returns [object Object] and [].toString() returns the contents of the array which is simply an empty string as the array holds nothing:

     ("[object Object]" + "")[!![] + !![] + !![]] + (![] + [])[!![] + !![] + !![]]
    
     ==>
    
     "[object Object]"[!![] + !![] + !![]] + (![] + [])[!![] + !![] + !![]]
    
  • When [] is converted to a boolean, it returns true. A logical !! returns true if its operand doesn't compare to undefined, null, 0, or an empty string "". Therefore !![] returns true.

    When arithmetic is done on boolean values, integral promotion is performed. The values true and false are converted to 1 and 0 respectively:

    "[object Object]"[true + true + true] + (![] + [])[true + true + true]
    
    ==>
    
    "[object Object]"[1 + 1 + 1] + (![] + [])[1 + 1 + 1]
    
    ==>
    
    "[object Object]"[3] + (![] + [])[3]
    
  • The subscript operator [n] obtains the (n + 1)-th member of an array-like structure (because arrays are 0-indexed). The first [3] obtains the 4th character of the string with is "j":

    "j" + (![] + [])[3]
    
  • ![] returns false (because [] is truthy) and [] returns an empty string:

    "j" + (false + "")[3]
    
    ==>
    
    "j" + "false"[3]
    
  • The 4th character in "false" is "s" (arrays are 0-indexed). So this resolves to:

    "j" + "s"
    
    ==> "js"
    
David G
  • 94,763
  • 41
  • 167
  • 253
1

If you look closely there are two things going on, one is addition of an empty object and an array, and the other is an indexer.

In JS, {} + [] returns 0

({} + []) returns "[object Object]"

[] + {} returns "[object Object]"

![] + {} returns "false[object Object]"

(![] + []) returns "false"

In addition, since everything is type-convertible, true+true = 2 (true being equivalent to 1). !![] will return true (the boolean) so !![] + !![] + ![] is the same as doing true + true + true which will equal 3.

So for this, you're evaluating things that come out as strings, then indexing over those strings to get the individual characters. You have anything in the words "false" and "Object" to choose from.

Thomas Jones
  • 4,892
  • 26
  • 34