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

{}[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:
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:
UPDATE
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) = undefined

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

You're not reversing the value of it.
![true] != [!true]
Check this out: Why is !true ? 'false' : 'true' returning 'true'?

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)[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!

Related

Difference between equality checking inside 'if condition' vs 'console.log' [duplicate]

This question already has answers here:
Empty arrays seem to equal true and false at the same time
(10 answers)
Closed 4 years ago.
I was trying out a code snippet and the results are different for an empty array check inside a console.log statement and in a conditional statement.
Help/Thoughts on why this is different?
Thanks in advance!
//Output: true
if([]) {
console.log(true)
} else{
console.log(false)
}
//Output: false
console.log([] == true)
You seem to be running into a known JavaScript quirk.
"[] is truthy, but not true"
The problem isn't where you are doing the evaluations, but rather that the two evaluations which seem identical are actually different.
See
https://github.com/denysdovhan/wtfjs#-is-truthy-but-not-true
My assumption is that the if/else block, in part of its "truthful" test is checking if something exists (not just if it is true or not) -- wherein the straight console print is comparing the value of the empty array against a boolean (which would be false)
let test = 'apple';
if( test ){
console.log( 'if/else: ' + true );
}else{
console.log( 'if/else: ' + false );
}
console.log( 'log: ' + ( test == true ) );
The two snippets are actually doing different things, hence the different results.
The first, with [] as the condition of the if statement, coerces the array to a Boolean value. (if, naturally enough, only works on Booleans, and JS will happily convert the given value if it isn't already Boolean.) This produces true - all objects in JS are "truthy", which includes all arrays.
For the second snippet, you are using the "loose equality" operator == - for which the JS specification provides a set of rules for how to convert the values into other types, eventually reaching a straightforward comparison between two values of the same type. You might want, or hope, that comparing a non-Boolean to true or false in this situation coerced the non-Boolean to Boolean - but this isn't what happens. What the specification says is that first the Boolean is coerced to number value - resulting in 1 for true (and 0 for false). So it reduces to [] == 1 - which will go through a few more conversions before resulting in a false result.
The key point is that no conversion to Boolean happens in the second case. If you think this is stupid, you're probably right. This is a bit of a gotcha, and one of the reasons many guides tell you never to use == in JS. I don't actually agree with that advice in general (and hate linters telling me to always use === in any circumstances) - but you do have to be aware of some dangers. And using == to compare a value to true or false is something to always avoid.
Luckily, if you want to test if x is truthy or falsy, you have a very short and understandable way to do it - the one you used in the first snippet here: if (x)
[edit] So my original answer was confusing as heck, and there are some incongruencies in the many answers you find on this subject all over the internet; so, let me try this again:
Part 1: Why they are Different
if([]) and if([] == true) are not the same operation. If you see the below example, you will get the same result when doing the same operation.
//Output: false
if([] == true) {
console.log(true);
} else{
console.log(false);
}
//Output: false
console.log([] == true);
Part 2: Why it matters AKA: the confusing bits
In JS, the following is a common expression used to see if an object/variable exists:
var foo = "Hello World";
if (foo) ...
From a design perspective, this test is not important to see if foo is equal to true or false, it is a test to see if the program can find the object or variable foo. If it finds foo, then it executes the results in the "then" condition, otherwise you get the "else" condition. So, in this case, it will convert foo to either false for does not exist, or true for does exist. So in this case the string is reduced to a boolean.
In contrast:
var foo = "Hello World";
if (foo == true) ...
Is typically trying to find out if the value of foo actually equals true. In this case, you are comparing the value of foo "Hello World" to a boolean, so in this case, "Hello World" does not equal true.
Just like foo, [] can be evaluated more than one way. An empty array is still an object; so, in the first case, it coerces to true because it wants to know if [] can be found; however, [] also equals ['']. So now picture this:
if (['bar'] == 'bar') ...
In this case, JS will not look at ['bar'] to see if it is there, but as an object containing a single value which it can convert to the string, 'bar'.
So:
if([]); // is true because it is an object test that evaluates as (1 === 1)
and
if([] == true) // is false because it is a string test that evaluates as ('' == 1) to (0 === 1)

Odd behaviour of comparison of object literals

I have searched but could not find logic behind following in JavaScript.
When I type in the Chrome console:
{} == null
it returns
Uncaught SyntaxError: Unexpected token ==
But
{} == {}
and
{} == function(){}
returns false
Why?
I assume you understand why {} == null throws SyntaxError. Long story short it is because { in the begining starting a block statement not an object literal. You could check the answer here
As of why {} == {} this works.
If you check chromium code that evaluates expressions in console. You could find the following (code)
if (/^\s*\{/.test(text) && /\}\s*$/.test(text))
text = '(' + text + ')';
executionContext.evaluate(text, "console", !!useCommandLineAPI, false, false, true, printResult);
This code wraps {} == {} code with parentheses making it a valid expression ({} == {}) comparing two empty object literals. Which evaluates to false because objects are compared by reference.
Node repl has the same behaviour src
if (/^\s*\{/.test(code) && /\}\s*$/.test(code)) {
// It's confusing for `{ a : 1 }` to be interpreted as a block
// statement rather than an object literal. So, we first try
// to wrap it in parentheses, so that it will be interpreted as
// an expression.
code = `(${code.trim()})\n`;
wrappedCmd = true;
}
You can find this in the specs under Statement (art. 12)
12 - Statement
Statement :
Block.
VariableStatement
EmptyStatement
ExpressionStatement
.
.
.
The first applicable rules are either Block or Expression Statement. So we need to look at 12.4.
In 12.4 the specs clearly state that an expression statement cannot start with a {.
though i haven’t yet found what makes example 2 an expression, maybe it’s implementation specific
12.4 Expression Statement
Syntax
ExpressionStatement :
[lookahead ∉ {{, function}] Expression ;
NOTE An ExpressionStatement cannot start with an opening curly brace because that might make it ambiguous with a Block. Also, an ExpressionStatement cannot start with the function keyword because that might make it ambiguous with a FunctionDeclaration.
Semantics
The production ExpressionStatement : [lookahead ∉ {{, function}]Expression; is evaluated as follows:
Let exprRef be the result of evaluating Expression.
Return (normal, GetValue(exprRef), empty).
I would say this is a parsing issue, rather than a logic issue per se.
In Chrome I get the observed behavior.
In IE I get syntax errors whenever I put {} (or, it seems, any object literal) on the LHS of the ==.
In both browsers, putting () around the expression fixed things. Or first assigning the object to a variable
var x = {}
x == null
I would say it seems to me like a bug in the parsing. Whether that is true in an academic sense would take digging through specs and grammars; the practical answer is, there are simple enough work-arounds that the best bet is to not do that.
It’s because JavaScript sucks
The reason it doesn’t work is because
JavaScript takes the type the comparison is taking from the first object.
For instance
3+”1” = 4
But
“3”+1 = 31
The first example does the operation as a number because the first object is a number
The second example sees a string as the first object and treats the operation as concatenation of a string.
For your example
{} is an object but null can’t be converted to an object
It works the other way because
{} can be represented as a null object.

Javascript Ternary Operator lvalue

I was reading about the ternary operator in different languages, and noticed something interesting in the Javascript section. http://en.wikipedia.org/wiki/%3F:#JavaScript
The conditional operator in JavaScript has the same syntax and precedence structure as in the other BCPL-derived variants, but a significant difference exists in the semantics: it returns an l-value.
The first sentence states that the return of the ternary in javascript is an lvalue, so I tried some examples, with odd results (in the chrome console).
Given:
var a = { 'yo' : 'momma' }
var b = { 'yo' : 'cool' }
var bool = true
(bool? a : b).yo = 'LLJ'
//a is now { 'yo' : 'LLJ' }
(bool? a.yo : b.yo) = 'LLJ' //throws a reference error
Why does the first work and the second fail? (Logically they're the same statements, no?)
Nope (it seems that Wikipedia's reference to "l-value" is misleading) - it is returning the value of the argument, not the reference to it; values in JavaScript cannot be assigned to directly1.
If you just did the following:
console.log(bool ? a.yo : b.yo);
// like doing the following:
'string' = 'eee';
... you would get a string - you can't assign to a string value/literal. All property references are converted to their value when passed into the conditional operator.
However, with an object, the reference value is an object, and since the property of an object is a reference, it works fine.
console.log(bool ? a : b); // you get an object, it's fine
The ECMAScript specification (that's the standard version of JavaScript) says that you can't get references (i.e. a l-value) from the conditional operator:
11.12 Conditional Operator ( ? : )
Let lref be the result of evaluating LogicalORExpression.
If ToBoolean(GetValue(lref)) is true, then:
Let trueRef be the result of evaluating the first AssignmentExpression.
Return GetValue(trueRef).
Else
Let falseRef be the result of evaluating the second AssignmentExpression.
Return GetValue(falseRef).
GetValue is an internal function that converts a reference to a value, therefore that's why you get a value, not a reference as you expected.
1: The internal assignment method in ECMAScript does not allow non-references to be assigned to:
8.7.2 PutValue (V, W)
If Type(V) is not Reference, throw a ReferenceError exception.
... (the rest is unimportant, my emphasis)
Wikipedia was wrong. The conditional operator returns an r-value, not an l-value.
The history of the article is quite interesting, so I've summarised it here:
30 August 2010: The Beginning
JavaScript section created. Correctly says that in JavaScript the ternary operator returns an r-value, but incorrectly says that in C/C++/Java it returns an l-value. Only in C++ the ternary operator returns an l-value.
31 January 2011: Cannot yield an l-value in C
C correctly removed from the JavaScript section because it doesn't return an l-value. Java remains.
15 February 2011: "Corrected"
The comparison to Java and C++ is removed (the comment correctly says that Java never yielded an l-value), but oh no! JavaScript suddenly returns an l-value!
7 March 2011: Hope is restored...
The incorrect "l-value" is changed to "value", linking to the Value article (which describes both l-values and r-values).
7 March 2011: ...but not for long
The link text is changed to say "l-value".
7 September 2013: Three cheers for Qantas 94 Heavy!
Thanks to this question, Wikipedia has been corrected.
Because the second line is not referencing the value of a.yo or b.yo, its referencing a flat object.
The first expression ends with .yo so it knows to reference the value of either a or b.
Has to do with how the js is actually implemented i guess...
But consider this..
(bool ? a: b) give a so the code becomes a.yo = 'LLJ', which is valid..
(bool ? a.yo : b.yo) gives what ever the string a.yo is holding. Essentially you're doing
'moma' = 'LLJ' which is invalid.
Here d becomes your set variable.
var obj = {'d' : 1, 'd1': 2}, obj2 = {'d': 2, 'd1': 2}, bool = true;
var dummyFn = function(obj, k, v) { obj['k'] = val; return obj; };
(bool ? (dummyFn(obj, 'd', (obj.d = newVal + 1))) : obj).d1 = newVal = 4;
console.log(obj.d);
The reason the code didn't work would be the same reason you can't replace dummyFn's value
with obj. Without a property to reference the object becomes anonymous.

explaining this declaration of the global namespace

I see this quite a lot at the top of scripts but I'm not completely sure what it means, can anyone explain?
var whatevername = whatevername || {};
It uses the OR operator to set default values. If whatevername has been set it will be used, otherwise a new empty object will be used.
An example:
function sayHi(options){
options = options || {};
if (options.useAlert){
alert("hi");
} else {
console.log("hi");
}
}
In this case you can always use the options parameter, even if it isn't passed to the function:
sayHi();
sayHi({"useAlert": true});
In the first case {} will be used and options.useAlert will be undefined. In the if statement that's the same as it being set to false and console.log will be used to print.
The OR operator is usually used like this:
if (hasAnEmailAddress || hasAPhoneNumber) {contactPerson()}
If hasAnEmailAddress is true the operator will return the value of hasAnEmailAddress instead of hasAPhoneNumber. If it isn't true the value of the second argument, hasAPhoneNumber will be returned.
That logic is used when setting default values: If the first argument is falsy return the second argument - even if it isn't a boolean value.
it initializes whatevername with an empty object if whatevername hasn't already been initialized.
Equivalent code
if(!whatevername) whatevername = {}
In a lot of languages, you will see this done with a ternary operator, which I think makes it very clear what's going on. Example:
var whatevername = (whatevername != NULL) ? whatevername : {};
In Javascript, if the || operator evaluates to truthy, it will not return a boolean value as one might expect, but the value of the operand which was last evaluated. Therefor, if whatevername is null, it will return a new object, otherwise it will return whatevername. Ruby does this as well, just to name another example of this behaviour.
This is a default value statement. || is the symbol for OR, as you probably know.
The statement reads "set whatevername to whatevername OR an empty object". The OR will pick the first of the two objects that reads to a truthy value (not empty, not false). If whatevername was set, you'll get whatevername. If not (or if set to null), you'll get an empty object.

When (and why) is {} undefined in a JavaScript console?

In the console of both FF and Chrome, {} is considered undefined until explicitly evaluated:
{}; // undefined
({}); // ▶ Object
Actually, it's a bit less defined than undefined -- it's apparently bad syntax:
{} === undefined; // SyntaxError: Unexpected token ===
{}.constructor; // SyntaxError: Unexpected token .
But not if it's on the other side, in which case it's fine:
"[object Object]" == {}.toString(); // true
Or if it's not the first expression:
undefined + undefined; // NaN
{} + undefined; // NaN
undefined + {}; // "undefined[object Object]"
What gives?
If you use the curly brackets by themselves, it's not an object literal, it's a code block. As the code block doesn't contain any code, evaluating it results in undefined.
Okay, here is my answer. There is nothing new here. I am just linking to (a pretty copy of) the ECMAScript specification for the grammar and showing a few productions to show "why" it parses the way it does. In any case, the behavior is well-defined according to the JavaScript/ECMAScript grammar rules: {} is parsed differently depending upon the "context" it is in.
The JavaScript REPLs ("consoles") start to parse the code in the Statement grammar production or "statement context". (This is actually a lie, it starts at the Program or SourceElements production, but that adds additional constructs to dig through.) Here is a rough grammar breakdown with simplifications and omissions; see the link above for more:
Statement
Block
...
ExpressionStatement
Block
# This is actually { StatementList[optional] }, but this is what
# it amounts to: * means "0 or more".
{ Statement* }
ExpressionStatement
# An ExpressionStatement can't start with "{" or "function" as
# "{" starts a Block and "function" starts a FunctionStatement.
[lookahead ∉ {{, function}]Expression ;
Expression
# This is really PrimaryExpression; I skipped a few steps.
...
( Expression )
Thus (when in "statement context"):
{}
-> Block # with no StatementList (or "0 statements")
-> Statement
And:
({})
-> (Expression)
-> Expression
-> ExpressionStatement # omitted in productions below
-> Statement
This also explains why undefined === {} parses as EXPR === EXPR -> EXPR -> STMT and results in false when evaluated. The {} in this case is in an "expression context".
In the case of {} === undefined it is parsed as {}; === undefined, or BLOCK; BOGUS -> STMT; BOGUS, which is a Syntax Error. However, with the addition of parenthesis this changes: ({} === undefined) is parsed as (EXPR === EXPR) -> (EXPR) -> EXPR -> STMT.
In the case of {} + "hi" it is parsed as {}; + "hi", or BLOCK; + EXPR -> STMT; EXPR -> STMT; STMT, which is valid syntax even though it is silly (+ is unary in this case). Likewise, just as above, "hi" + {} puts the {} into an "expression context" and it is parsed as EXPR + EXPR -> EXPR -> STMT.
The JavaScript console is just showing the result of the last Statement, which is "undefined" (well, "nothing" really, but that doesn't exist) for an empty {} block. (This might vary between browsers/environments as to what is returned in this case, e.g. last ExpressionStatement only?)
Happy coding.
If you just type {} as input in any console, there is no context to interpret what you want the curly braces to mean, other than it's position. given the fact each input to the console is interpreted as fresh line of code, the opening curly brace is seen as the start of a new block. The closing } is syntactically correct, since an empty block is often used in situations like these:
try
{
//something
}
catch(e)
{}//suppress error
Hence {} will always be undefined when it is on the left hand side, and never spit errors as an empty block is valid code.
It seems like both consoles treat it as an ambiguous condition when the expression starts with {. Maybe it is treated as a dummy block.
Try this:
{} // undefined
undefined === {} // false
Using {} as a right-hand-expression removes the ambiguity.
Also you can see from:
{a:42} // 42
{{a:42}} // 42
{{{a:42}}} // 42
That the outer braces are really treated as a dummy block.
And this doesn't seem to be a console feature. Even eval treats them like that, hinting to the fact that the stuff you type in the console actually get evaluated the same way they would when passed to eval:
eval("{}") // undefined
eval("{alert(42)}") // alerts 42
The problem is that in some cases, javascript sees { and } as opening and closing a /block/. While in other cases, {} is an object. The cases really depend on the context.
Doug Crockford complains about this. That WTF you're getting there is due to the + operator itself. It's used to both to arithmetic and concatenate. In your last line there, you're seeing the + operator convert undefined and the empty object to strings, and concatenating them.
Javascript separates the concept of statements and expressions (languages like C++ or Java do the same).
For example if ... is a statement, and x?y:z is an expression.
Expressions have a value, statements do not.
One problem with Javascript syntax is that {} can be either an expression (and in this case it means an empty object constructor) or a statement (and in this case it means an empty code block... basically a NOP) so how it's interpreted depends on the context.

Categories