3

Assuming you have a browser that supports both labeled function declarations and block statements, what is the standard way/method for browsers to determine if the following is an object with a property named L that is function F, or a block that contains function F labeled as L:

{
    L: function F(){}
}

E.g.

To expose what I mean, here are two different copies of the above code modified to expose it as an array and as a function:

document.body.textContent = typeof( () => {
    L: function F(){}
} )

In the above code, the browser recognizes the arrow function notation and determines that it is a block statement. However,

document.body.textContent = typeof {
    L: function F(){}
}

The above code makes the browser think that it is an object written out as an object literal with index L being function F

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143

2 Answers2

3

You can reduce the question to: How does the browser know whether { starts a block and when does it start an object literal?

And the answer to that is that JS engines will treat { as the start of a block if it appears in a statement position and as the start of an object literal if it is in an expression position.

That's the reason why you have to add parenthesis (()) around {} when they appear in a statement position but you want an object instead.

The introduction of labeled function declarations doesn't change the circumstances at all because the situation was already ambiguous:

{
  foo: 42
}

Looking at the spec again, this ambiguity is actually pointed out:

An ExpressionStatement cannot start with a U+007B (LEFT CURLY BRACKET) because that might make it ambiguous with a Block.

(and the grammar reflects that too)

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 1
    Could you please add a citation to where in the standards it says this. (I agree full-heartedly with this, but I am still curious about the gorey details) – 3.1415926535897932384626433833 Jun 15 '17 at 23:05
  • 2
    It's not written as such in the spec, but it follows from the grammar rules: https://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-statements-and-declarations . – Felix Kling Jun 15 '17 at 23:06
  • 1
    The parser simply tries to match rules. At the top you have a *Script*, which has as *ScriptBody*, which has a list of *Statement*s, etc. – Felix Kling Jun 15 '17 at 23:12
  • 1
    An exception to this is the arrow notation. For example, with the arrow notation, if `() => 3` creates a function that returns 3, then logically `() => { L: function F(){} }` should create a function that returns an object. But it isn't this way which means it must be more complicated. – 3.1415926535897932384626433833 Jun 15 '17 at 23:46
  • 2
    Not that much more complicated, but yes, there are extra rules for arrow functions: https://www.ecma-international.org/ecma-262/7.0/#sec-arrow-function-definitions . The body can either be an expression that does *not* start with `{` or it can be `{` followed by a list of statements, followed by `}`. – Felix Kling Jun 15 '17 at 23:48
  • 1
    It is actually quite explicit in the spec. Updated my answer. – Felix Kling Jun 15 '17 at 23:53
1

Well... I think that:

if(1){ // the brackets here belong to the if statement == block
    L: function F(){}
}

While here:

console.log({ // the brackets represent JSON (javascript object notation) 
    L: function F(){}
})

This is indeed an object with 'L' index

ymz
  • 6,602
  • 1
  • 20
  • 39