{}[true]
is [true]
and ![true]
should be false
.
So why does !{}[true]
evaluate to 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
!
You're not reversing the value of it.
![true] != [!true]
Check this out: Why is !true ? 'false' : 'true' returning 'true'?
{}[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.
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() {
//...
}
{}
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
.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