Reputation: 8178
I read this line in Eloquent JavaScript and would love some clarity.
...braces have two meanings in JavaScript. At the start of a statement, they start a block fo statements. In any other position, they describe an object. Fortunately, it is almost never useful to start a statement with a brace object, and...
So, braces in let's say a..... an 'if statement' create a block of statements to execute, but braces that appear in let's say a function call (as a parameter) or in a variable assignment becomes an object literal.
Is that right? What are all the other cases? I'm not sure I understand the rule for when braces bundle up statements and for when they describe an object.
Upvotes: 1
Views: 525
Reputation: 875
var a = {field1:value1, field2:value2}
function func() {
// do something
}
var f = function() { /* do something */ };
var f = ()=>{}; // ditto
// {}.toString(); // syntax error, first brace of statement = code block
({}).toString(); // correct
var obj = {a:1, b:2, c:3};
var {a:x, c:y} = obj; // assign obj.a to x, and obj.c to y
({a:x, c:y} = obj); // ditto
Note - this has a lot of forms so I won't cover them all, full info found here (thanks RobG)
You can assume that all your JS code is inside some {}
block. So the start of your code is immediately after a {
always.
Wherever a value is expected, {}
does not mean a function body. At the start of a statement this is ambiguous because you can have anonymous code blocks like so:
var x = 1;
{
var x = x+2;
// x = 3
}
// x = 3 (!)
This is archaic from C-style syntax where this would influence scope, but in testing this in JS it doesn't seem to have that effect, so for all intents it's rather useless syntax except to identify a code block. If you wanted such behavior you'd need to do this:
var x = 1;
(()=>{
var x = x+2;
// x = 3
})()
// x = 1
If we need an object first in some statement, we need to clarify to JS that we want a value. This is why we use ({})
instead of {}
, because the former is unambiguously an object literal inside parens.
Rather than examine when {}
is parsed as a value, let's look at when it isn't. There are two cases in general where we don't treat {}
as an object literal: as a function body or as a statement group (my own term).
Consider the general control statements - if
, for
, while
, with
etc. These can all* be used in a way that completely avoids {}
. In this respect {}
should be thought of as statement groups hence the term.
if (x) x++; else x--;
if (x) {x++;} else {x--;}
{if (x) {x++;} else {x--;}}
*note: switch
is an exception, switch(1);
gives an error SyntaxError: missing { before switch body
Using this rule it then makes sense why we must use ()
to denote an object literal if it's the start of a statement - we can't start a statement in ()
, so you can't start a statement group there either, leaving only one option (object literal or related syntax).
This leaves function bodies.
First, consider a function declaration statement:
function f () {}
It doesn't need a semicolon (;
). This means the entire thing is a single statement. This explains why the following gives a syntax error in the first form but not the second:
function(){return 1;}(); // error: function statement requires name
var x = function(){return 1;}(); // fine
This is because the first is parsed as a statement, and a function declaration statement cannot be anonymous. However the second is in a value context and is treated as such. The situation is identical as with object literals, if it could be a statement it cannot be a value, but if we're already knee deep in value land, it has to be a value.
The =>
notation is, with one exception, parsed identically to function
. The ()=>{}
form is identical but in practice differs because this type of function cannot have a this
object - it cannot be an object method (doesn't make much sense to) and it cannot construct new objects (it has no prototype), and other quirks as a result. otherwise it's straightforward to see how it's the same as function(){}
.
()=>...
however is a little different. It's treated as ()=>{return ...}
. But, without the explicit }
to finish the return statement, the syntax greedily captures the largest expression that would parse as such (not necessarily work). Case in point:
()=>1; // statement; = function that returns "1"
()=>1(); // statement; = function that returns "1()"
(()=>1()); // TypeError: 1 is not a function
(()=>1)(); // what was intended in above (you'd hope)
Upvotes: 3