175

The new ES6 arrow functions say return is implicit under some circumstances:

The expression is also the implicit return value of that function.

In what cases do I need to use return with ES6 arrow functions?

double-beep
  • 3,889
  • 12
  • 24
  • 35
Jess Telford
  • 11,402
  • 8
  • 39
  • 50

6 Answers6

292

Jackson has partially answered this in a similar question:

Implicit return, but only if there is no block.

  • This will result in errors when a one-liner expands to multiple lines and the programmer forgets to add a return.
  • Implicit return is syntactically ambiguous. (name) => {id: name}returns the object {id: name}... right? Wrong. It returns undefined. Those braces are an explicit block. id: is a label.

I would add to this the definition of a block:

A block statement (or compound statement in other languages) is used to group zero or more statements. The block is delimited by a pair of curly brackets.

Examples:

// returns: undefined
// explanation: an empty block with an implicit return
((name) => {})() 

// returns: 'Hi Jess'
// explanation: no block means implicit return
((name) => 'Hi ' + name)('Jess')

// returns: undefined
// explanation: explicit return required inside block, but is missing.
((name) => {'Hi ' + name})('Jess')

// returns: 'Hi Jess'
// explanation: explicit return in block exists
((name) => {return 'Hi ' + name})('Jess') 

// returns: undefined
// explanation: a block containing a single label. No explicit return.
// more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label
((name) => {id: name})('Jess') 

// returns: {id: 'Jess'}
// explanation: implicit return of expression ( ) which evaluates to an object
((name) => ({id: name}))('Jess') 

// returns: {id: 'Jess'}
// explanation: explicit return inside block returns object
((name) => {return {id: name}})('Jess') 
Community
  • 1
  • 1
Jess Telford
  • 11,402
  • 8
  • 39
  • 50
  • I don't get that syntax.. are you creating a class using a class littoral and then calling an implied constructor with one argument ('Jess')?? I thought you would to this ((name) => ({id: 'Jess'})) – Michael Dausmann Jul 14 '15 at 08:50
  • 3
    @MichaelDausmann It's an arrow function that has one parameter, `name`, with the function enclosed in parentheses and invoked with one argument, "Jess". Code between the `=>` and `)('Jess')` in each case is the body of the arrow function. Consider it like a short form of an Immediately Invoked Function Expression of the form `(function (name) { return { id: name } })('Jess')` – Russ Cam Jul 14 '15 at 12:59
  • Very useful indded! helps spot problems in Promises.all that map over items with an arrow function and you can notice if you get an array of undefined if no value was returned for mapping over array with arrow functions. – jay shah Oct 06 '16 at 13:07
  • What would have been the downside of making implicit return systematic for arrow functions? Just like coffeescript does... (though I don't like coffeescript) – Augustin Riedinger Feb 16 '17 at 16:04
  • 6
    To be clear, it seems that because the JS parser doesn't know whether to expect an *expression* (such as an expression containing an object literal `{}`) or a *block*, it assumes that a `{ }` denotes a block. That means that when it sees `id: name`, it thinks `id:` is an expression creating a [label](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label) (a very uncommonly-used feature of JS that deals with flow control and uses a `:`), and then the `name` following `id:` is simply a separate statement that only contains the variable `name` (& does nothing). – iono Jul 31 '18 at 17:32
  • The "one-liner" can span several lines as long as it's a single sentence. – Juan Lanus Mar 24 '21 at 12:50
  • so one can't use "return" keyword inside parenthesis right ? I can be only used along with curly braces ? – vikramvi Apr 07 '21 at 10:56
22

I understand this rule-of-thumb ...

For functions that are effectively transforms (one-line-manipulations of arguments), return is implicit.

Candidates are:

// square-root 
value => Math.sqrt(value)

// sum
(a,b) => a+b

For other operations (more than one-liners that require a block, return has to be explicit

Amarsh
  • 9,434
  • 18
  • 43
  • 73
12

There's another case here.

When writing a functional component in React, you can use parentheses to wrap implicitly returned JSX.

const FunctionalComponent = () => (
  <div>
    <OtherComponent />
  </div>
);
Deci
  • 129
  • 1
  • 5
6

Here's another case that gave me some trouble.

// the "tricky" way
const wrap = (foo) => (bar) => {
  if (foo === 'foo') return foo + ' ' + bar;
  return 'nofoo ' + bar;
}

Here we define a function returning an anonymous function.The "tricky" bit is that the function body for the outer function (the part begining with (bar) => ...) visually looks like a "block", but it's not. Since it's not, implicit return kicks in.

Here's how wrap would execute:

// use wrap() to create a function withfoo()
const withfoo = wrap('foo');
// returns: foo bar
console.log(withfoo('bar'));

// use wrap() to create a function withoutfoo()
const withoutfoo = wrap('bar');
// returns: nofoo bar
console.log(withoutfoo('bar'));

The way I unpacked this to make sure I understood it was to "unarrowify" the functions.

Here's the semantic equivalent of the first code block, simply making the body of wrap() do an explicit return. This definition produces the same results as above. This is where the dots connect. Compare the first code block above with the one below, and it's clear that an arrow function itself is treated as an expression, not a block, and has the implied return.

// the explicit return way
const wrap = (foo) => {
  return (bar) => {
    if (foo === 'foo') return foo + ' ' + bar;
    return 'nofoo ' + bar;
  }
}

The fully unarrowified version of wrap would be like this, which while not as compact as the fat arrowed up version, seems a lot easier to comprehend.

// the "no arrow functions" way
const wrap = function(foo) {
  return function(bar) {
    if (foo === 'foo') return foo + ' ' + bar;
    return 'nofoo ' + bar;
  };
};

In the end, for others that may have to read my code, and future me, I think I'd prefer to go the non arrow version which can be comprehended visually at first glance, rather than the arrow one which takes a fair bit of thought (and in my case experimentation) to grok.

grayjohn
  • 61
  • 2
  • 2
3

Arrow functions allow you to have an implicit return: values are returned without having to use the return keyword.

It works when there is a on-line statement in the function body:

const myFunction = () => 'test'

console.log(myFunction()) //'test'

Another example, returning an object (remember to wrap the curly brackets in parentheses to avoid it being considered the wrapping function body brackets):

const myFunction = () => ({value: 'test'})

console.log(myFunction()) //{value: 'test'}
Flavio Copes
  • 3,482
  • 3
  • 23
  • 29
  • 1
    This should be the correct answer, albeit needing a bit more explanation. Basically when the function body is an expression, not a block, that expression's value is returned implicitly. Correct me if I'm wrong. – Paul-Sebastian Manole Apr 27 '19 at 18:39
0

Omitting the brackets {} and return keyword from an arrow function are ok if: (1) You wouldn't have any code (e.g. assignment statements) before the return statement and (2) You would be returning a single entity [Note: The single entity can be multiple lines. If so, then all you need are regular parentheses() like the example below:

posts.map(post => (
  <li key={post.id}>
    {post.title}
  </li>
))
rob_abcba
  • 36
  • 2