Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

javascript

People also ask

Why True true is false in JS?

A core mechanic of Javascript is the ability to distinguish between true and false values. The Javascript standard defines true and false values as a unique data type called a Javascript boolean. Javascript booleans may be true , false , or (in certain contexts) a value that evaluates to either true or false .

What does true or true evaluate to?

TRUE (say: not true) to evaluate to FALSE and ! FALSE (say: not false) to evaluate to TRUE. Try using the NOT operator and the equals operator to find the opposite of whether 5 is equal to 7. Let's take a moment to review.

What evaluates to true JavaScript?

In JavaScript, a truthy value is a value that is considered true when encountered in a Boolean context. All values are truthy unless they are defined as falsy. That is, all values are truthy except false , 0 , -0 , 0n , "" , null , undefined , and NaN .

Why does [] === [] return false?

Note that === never causes type coercion, but checks for correct types first and yields false if they are not equal! Only if the types are equal, it compares the actual values. So this method of comparison is far more reliable than == .


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


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

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


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.


{}[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.


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