ES2015 Arrow Functions: Implicit Return

Recently I noticed “An Introduction to JavaScript ES6 Arrow Functions”, by Alex Gorbatchev (whose SyntaxHighlighter I’m using here :)) and want to clarify some of its points.

Implicit Return

It says…

single line arrow functions perform an implicit return

…which it later means to clarify with:

When we talk about single statement arrow functions, it doesn’t mean the statement can’t be spread out to multiple lines for better comprehension.

And, in bold:

Implicit return only happens for single statement arrow functions.

The issue with these descriptions are the references to statements and lines. Implicit return works only when there are no statements, and lines are irrelevant (although obviously this syntax facilitates writing “one-liners”).

Both issues are resolved by explaining that implicit return works only when the function body (technically ConciseBody) consists of an AssignmentExpression instead of a block. (With the caveat that the AssignmentExpression can not begin with an ObjectLiteral because of the ambiguity with the {, though it can of course begin with a ( followed by an ObjectLiteral.)

It’s an important distinction because a single statement without a block is invalid in this context, and implicit return won’t happen with a single statement (or any number) inside a block (as explained in the article). I’ll illustrate the difference:

Single statement (not valid):

log(x => return "y");
log(x => var y = "y");

Single statement (won’t return):

log(x => { "y"; });
log(x => { var y = "y"; });

The following function bodies are expressions, are valid, and will return:

log(x => "y");
log(x => x ? "y" : undefined);
log(x => x && "y" || undefined);

log(x =>
  x ?
  "y" :
  undefined
);

log(x =>
  x && "y" ||
  undefined
);

So implicit return happens when the function body is an expression (which requires omitting the braces that would create a block), which can of course be formatted like any other expression in JS (e.g. with line breaks).

Rest / Spread

Regarding arguments, the article says:

Having said that, you can still get all arguments passed into the arrow functions using rest parameters (also known as spread operator):

While rest and spread are related concepts that use similar syntax, and there is a sort of symmetry, especially when a rest param is spread as illustrated below, they are fundamentally different operations and referring to them as if synonymous muddles things. Example:

// rest (FunctionRestParameter : BindingRestElement)
(...args) => {
  console.log(
    // spread (...AssignmentExpression)
    ...args,

    // spread (...AssignmentExpression)
    ...[1, 2, 3],

    // spread (SpreadElement : ...AssignmentExpression)
    [...args],
  )
}

On a nittier note, I just noticed that the ECMAScript spec never actually refers to the ... in rest or spread syntax as an operator (though other, unofficial, sources like MDN do). It does classify it as a punctuator. But in a context like this article I think it makes sense to refer to it as an operator. Well, as 2 operators: rest and spread.

Use Cases

As it’s bottom line the article recommends use cases for arrow functions, one of which is working with the enclosing scope’s this. To that I’ll add that working with the enclosing scope’s super, arguments, or new.target are also use cases to keep in mind.

Leave a Reply

Your email address will not be published. Required fields are marked *

Note: Comments are moderated. Spam comments will never be published.

Is this comment spam?