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 .
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.
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 .
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:
With Firefox, it also evaluates to true
:
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) = undefinedIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With