{}[true]
is [true]
and ![true]
should be false
.
So why does !{}[true]
evaluate to true
?
{}[true]
is [true]
and ![true]
should be false
.
So why does !{}[true]
evaluate to true
?
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
:
'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:
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) = undefinedThis 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() {
//...
}
{}
is an object with no properties.[]
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"
)true
(since it has no properties) so {}['true']
is undefined
!undefined
casts undefined
to a boolean (false
)false
into true
.You're not reversing the value of it.
![true] != [!true]
Check this out: Why is !true ? 'false' : 'true' returning 'true'?
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
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.
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.
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)[Best way to break from nested loops in Javascript?, (3)[How to break nested 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
!