Why does !{}[true] evaluate to true in JavaScript?

Javascript

Javascript Problem Overview


{}[true] is [true] and ![true] should be false.

So why does !{}[true] evaluate to true?

Javascript Solutions


Solution 1 - Javascript

I believe that's because plain {}[true] is parsed as an empty statement block (not an object literal) followed by an array containing true, which is true.

On the other hand, applying the ! operator makes the parser interpret {} as an object literal, so the following {}[true] becomes a member access that returns undefined, and !{}[true] is indeed true (as !undefined is true).

Solution 2 - Javascript

Because {}[true] does not return true, but undefined, and undefined is evaluated as false:

http://jsfiddle.net/67GEu/

'use strict';
var b = {}[true];
alert(b); // undefined
b = !{}[true];
alert(b); // true

Solution 3 - Javascript

Because

{}[true]

evaluates to undefined, and !undefined is true.

From @schlingel:

true is used as key and {} as hash map. There doesn't exist an property with the key true so it returns undefined. Not undefined is true, as expected.

Console session (Node.js [0.10.17]):

> {}[true]
undefined
> !{}[true]
true
> [true]
[ true ]
> ![true]
false
>

However, in the Google Chrome console:

> !{}[true]
true

So, no inconsistencies. You're probably using an old version of the JavaScript VM. For those who need further evidence:

Enter image description here

UPDATE

With Firefox, it also evaluates to true:

Enter image description here

Solution 4 - Javascript

The reason for the confusion is down to a misunderstanding of your first assertion:

{}[true] is [true]

What you're seeing when you run it is the result of an ambiguity. Javascript has a defined set of rules as to how to handle ambiguities like this, and in this case, it breaks what you see as a signle statement down into two separate statements.

So Javascript sees the above code as two separate statements: Firstly, there is a {}, and then there is an entirely separate [true]. The second statement is what is giving you the result [true]. The first statement {} is effetively entirely ignored.

You can prove this by trying the following:

({}[true])

ie wrapping the whole thing in brackets to force the interpreter to read it as a single statement.

Now you'll see that the actual value of your statement is undefined. (this will also help us later to understand the next part)

Now we know that the initial part of your question is a red herring, so let's move onto the final part of the question:

> So why does !{}[true] evaluate to true?

Here, we have the same statement, but with a ! appended to the front of it.

In this case, Javascript's rules tell it to evaluates the entire thing as a single statement.

Refer back to what happened when we wrapped the earlier statement in brackets; we got undefined. This time, we are effectively doing the same thing, but putting a ! in front of it. So your code can be simplified as !undefined, which is true.

Hopefully that explains it a bit.

It is a complex beast, but the lesson to learn here is to use brackets around your statements when evaluating them in the console, to avoid spurious results like this.

Solution 5 - Javascript

{}[true] is undefined. To find that write this:

a = {};
a[true] === undefined // true

or simply:

({})[true] === undefined // true

We know that !undefined is true.


From @Benjamin Gruenbaum's answer:

>Chrome dveloper tools does the following:

  try {
      if (injectCommandLineAPI && inspectedWindow.console) {
          inspectedWindow.console._commandLineAPI = new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null);
          expression = "with ((window && window.console && window.console._commandLineAPI) || {}) {\n" + expression + "\n}";
      }
      var result = evalFunction.call(object, expression);
      if (objectGroup === "console")
          this._lastResult = result;
      return result;
  } 
  finally {
      if (injectCommandLineAPI && inspectedWindow.console)
          delete inspectedWindow.console._commandLineAPI;
  }

>So basically, it performs a call on the object with the expression. The expression being:

with ((window && window.console && window.console._commandLineAPI) || {}) {
    {}+{};// <-- This is your code
}

>So, as you can see, the expression is being evaluted directly, without the wrapping parenthesis.

More information can be found in this question.

Solution 6 - Javascript

The answers here are good, here's a breakdown in pseudo-code:

  • {}['whatever'] = empty block, NewArray('whatever') = NewArray('whatever')
  • {}[true] = empty block, NewArray(true) = NewArray(true)
  • !{}['whatever'] = LogicalNOT(convertToBool(NewObject.whatever)) = LogicalNOT(convertToBool(undefined)) = LogicalNOT(false) = true
  • ({}['whatever']) = Grouping(NewObject.whatever) = Grouping(undefined) = undefined

Solution 7 - Javascript

This happens because {} in your meaning is not literal presentation of Object, but empty scope ( or empty code block ):

{ var a = 1 }[true] // [true] (do the same thing)

It just evaluates code inside scope and then shows you your array.

And from your

!{}[true]

Just converts to int this scope and return same array true. There is no bool checks in this code.

And if you will try to check result from {}[true] you will get your false:

{}[true] -> [true] -> ![true] -> false

As there is no more any scope.

So ! in your question do the same as:

!function() {
   //...
}

Solution 8 - Javascript

  • {} is an object with no properties.
  • Since [] immediately follows an object, it means "Access a property of this name" and not "Create an array"
  • true is a boolean, but is being used as an property name so it is cast to a string ("true")
  • The object does not have a property called true (since it has no properties) so {}['true'] is undefined
  • !undefined casts undefined to a boolean (false)
  • The not operator turns false into true.

Solution 9 - Javascript

You're not reversing the value of it.

![true] != [!true]

Check this out: https://stackoverflow.com/questions/5591139/why-is-true-false-true-returning-true

Solution 10 - Javascript

#Let's Play a Little More!

First, let's have some fun!:

//----------#01#-----------
{}[true]; //[true]

//----------#02#-----------
var a = {}[true]; 
	  console.log(a); //undefined

//----------#03#-----------
{ b: 12345 }[true]; //[true]

//----------#04#-----------
{ b: 12345 }["b"]; //evaluates to ["b"] ?!?

//----------#05#-----------
{ b: 12345 }.b; // "Unexpected token ."

//----------#06#-----------
({ b: 12345 }).b; //12345

//----------#07#-----------
var c = { b: 12345 }.b; 
	  console.log(c); //12345

//----------#08#-----------
var c = { b: 12345 }["b"];
	  console.log(c); //12345

//----------#09#-----------
{ true: 54321 }[true]; // "SyntaxError: Unexpected token : "

//----------#10#-----------
var d = { true: 54321 }[true]; //No error here ¬¬
	  console.log(d); //54321

//----------#11#-----------
!{}[true]; // true

##Ok, let's try to understand these crazy behaviors, one by one: 1) Here, the {} is parsed as an empty code block. Without an assign, negation, grouping (with parentheses) or any syntax which indicates to the parser that this {} is an object literal, the default assumption is to think it is simply a useless empty block.

This is a proof of this behavior:

{ alert(123) }[true]

The code above will show the alert normally, and will be evaluated as [true], in the same way {}[true] is.

###Block Statements Without Semicolons A block-type statement doesn't need a semicolon after it.

For instance:

for(var i=0; i < 1; i++){}function a(){};alert("Passed here!");if(true){}alert("Passed here too!")

Both alerts are shown.

So, we can see that an empty block statement, without a semicolon, is valid and simply does nothing. This way, when you enter {}[true] in the Developer Tools (or Firebug) Console, the evaluated value will be the value of the last expression statement. In this case, the last expression statement is [true].

2) In an assignment context, the parser will make sure that {} is an object literal. When you do var a = {}[true], you remove any ambiguity and tip the parser off that {} is not a block statement.
So, here, you're trying to get a value with a key "true" from an empty object. Obviously, there's no key-value pair with this key name. This way, the a variable is undefined.

###Reserved words as Object keys ECMAScript 5 allows object keys to be reserved words. So, the following keys are legal:

var obj = {if: 111, for: 222, switch: 333, function: 444, true: 555}

3) The same explanation of example 1. But... If the { b: 12345 } part is treated as a block statement, what's the type of the b: 12345 statement??

... (?????)

It's a label statement, you already saw it before... It's used in loops and in switch. Here are a few interesting links about label statements: 1, (2)[https://stackoverflow.com/questions/183161/best-way-to-break-from-nested-loops-in-javascript], (3)[https://stackoverflow.com/questions/1564818/how-to-break-2-loops-in-javascript].

NOTE: Just try to evaluate this:

{a: 1, b: 2} //=>>>SyntaxError: Unexpected token :

Label statements can't be separeted by the comma operator, you would need to separate them with a semicolon. So this is valid: {a: 1; b: 2}

4) See the explanations for the examples 1 and 3...

5) One more time, we have a { b: 12345 } being treated as a code block, and you're trying to access a property of a code block by using the dot notation, and obviously, this is not allowed, and the parser throws an "Unexpected token :" exception.

6) The code is almost identical to the above example, but by surrounding the { b: 12345 } statement with the expression grouping operator, the parser will know that is an object. This way, you'll be able to access the "b" property normally.

7) Remember the example 2, we have an assignment here, the parser knows that { b: 12345 } is an object.

8) Identical to the above example, but instead of the dot notation, here we're using the bracket notation.

9) I already said that this "identifier: value" syntax inside a block statement is a label. But, you also have to know that a label name can't be a reserved keyword (the opposite of object property names). When we tried to define a label called "true", we got a SyntaxError.

10) Again, we're dealing with an object. No problems using reserved words here. =)

11) Finally, we have this: !{}[true]

Let's separate the things here:

a) By doing a negation, we're informing to the parser that the {} is an object.

b) As shown in the example 2, a {} object doesn't have a property called true, so this expression will evaluate to undefined.

c) The final result is the negation of undefined value. Javascript performs implicity type conversion, and undefined value is falsy.

d) So, the negation of false is... true!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2430508View Question on Stackoverflow
Solution 1 - JavascriptFrédéric HamidiView Answer on Stackoverflow
Solution 2 - JavascriptdooxeView Answer on Stackoverflow
Solution 3 - JavascriptGames BrainiacView Answer on Stackoverflow
Solution 4 - JavascriptSpudleyView Answer on Stackoverflow
Solution 5 - JavascriptIonică BizăuView Answer on Stackoverflow
Solution 6 - JavascriptBen LeshView Answer on Stackoverflow
Solution 7 - JavascriptantyratView Answer on Stackoverflow
Solution 8 - JavascriptQuentinView Answer on Stackoverflow
Solution 9 - JavascriptDropoutView Answer on Stackoverflow
Solution 10 - JavascriptAlcides QueirozView Answer on Stackoverflow