Semicolons must follow statements. They do not need to keep track of the blocks. For example, here is an unnecessary semicolon with if :
if(foo === bar) {
A semicolon after an if block if never required.
What does this have to do with your case? Well, sometimes { ... } is a block, and sometimes { ... } is an object literal. The surrounding context allows the grammar to determine what it is. In your first case, this is an object; in the second case, it is a block.
The characters following the return on the same line are parsed as an expression. When { ... } parsed as an expression, it is an object literal. In your first example, return { ... } is a return statement with an object expression. It must have a semicolon because it is a statement.
It is important to understand here that ECMAScript does not allow line breaks to separate return and expression for the return value . This is in ES2015 & # xa7; 11.9.1, Rules for automatic semicolon insertion :
ReturnStatement [Yield] :
return [no LineTerminator here] Expression ;return [no LineTerminator here] Expression [In ,? Yield] ;
ReturnStatement cannot have a LineTerminator character between return and expression.
Since you have a newline between your return and { ... } , the { ... } not parsed as belonging to return . It is autonomous, which means that it is analyzed as a block. A sequence { ... } can only be parsed as an object when it is part of a larger statement or expression, for example
foo = { ... }- function argument (
bar({ ... } ) - return value (
return { ... } ) - and etc.
When { ... } is purely on one line, it is treated as a block.
Since the second case has a block, not an object, it does not need a semicolon, as described at the beginning of this answer.