837

When returning an object from an arrow function, it seems that it is necessary to use an extra set of {} and a return keyword because of an ambiguity in the grammar.

That means I can’t write p => {foo: "bar"}, but have to write p => { return {foo: "bar"}; }.

If the arrow function returns anything other than an object, the {} and return are unnecessary, e.g.: p => "foo".

p => {foo: "bar"} returns undefined.

A modified p => {"foo": "bar"} throws SyntaxError: unexpected token: ':'”.

Is there something obvious I am missing?

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Jonathan Schneider
  • 26,852
  • 13
  • 75
  • 99
  • 1
    I'm not clear when to use return keyword and when not to use it, JS being very very flexible creates loads of bugs for new users of this language. I wish it was as strict like "Java" language – vikramvi Apr 07 '21 at 10:47
  • arrow functions is the the worst feature of es6 in terms of code readability. hate them so much. – Semra Feb 26 '23 at 12:57

6 Answers6

1409

You must wrap the returning object literal into parentheses. Otherwise curly braces will be considered to denote the function’s body. The following works:

p => ({ foo: 'bar' })

You don't need to wrap any other expression into parentheses:

p => 10
p => 'foo'
p => true
p => [1,2,3]
p => null
p => /^foo$/

and so on.

Reference: MDN - Returning object literals

iono
  • 2,575
  • 1
  • 28
  • 36
alexpods
  • 47,475
  • 10
  • 100
  • 94
  • 14
    I'm curious *why* the parens make a difference. – wrschneider Jan 18 '17 at 02:28
  • 69
    @wrschneider because without parens js parser thinks that its a function body, not an object, and foo is [a label](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label) – alexpods Jan 18 '17 at 13:31
  • 28
    @wrschneider more specifically, in terms of AST nodes, using parentheses denotes an expression statement, in which an object expression can exist, whereas by default, curly braces are interpreted as a block statement. – Patrick Roberts May 20 '17 at 07:43
  • 8
    No idea why this works, but if you want to use the value of `p` as key for the object literal, this is how you do it: `p => ({ [p]: 'bar' })`. Without the `[]`, it'll either be `undefined` or literally the letter `p`. – DanMan Oct 03 '18 at 23:52
  • 8
    @DanMan It's called [computed properties](https://developer.mozilla.org/pt-PT/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names) and it's a feature of object literals. – D. Pardal May 04 '20 at 15:13
  • why we don't have to use return keyword inside parenthesis ? – vikramvi Apr 07 '21 at 10:46
  • 4
    @vikramvi Because `p => ({ foo: 'bar' })` is the same as `p => { return { foo: 'bar' }; }`. It's a shorthand syntax. – Adrian Wiik Apr 11 '22 at 11:02
79

You may wonder, why the syntax is valid (but not working as expected):

var func = p => { foo: "bar" }

It's because of JavaScript's label syntax:

So if you transpile the above code to ES5, it should look like:

var func = function (p) {
  foo:
  "bar"; //obviously no return here!
}
Petr Odut
  • 1,667
  • 14
  • 7
  • 9
    Labels are such a seldom used and esoteric feature. Do they REALLY have any value? I feel like they should be deprecated and eventually removed. – Kenmore Feb 27 '19 at 21:51
  • 6
    @Kenmore See https://stackoverflow.com/questions/55934490/why-are-await-and-async-valid-variable-names/55934491#55934491 - backwards compatibility. *Browsers will refuse to implement a feature which breaks existing sites* – CertainPerformance Jun 11 '19 at 07:29
  • 5
    @Kenmore you can exit from nested loops if they are labeled. Not often used but definitely useful. – Petr Odut Jun 26 '19 at 14:24
24

If the body of the arrow function is wrapped in curly braces, it is not implicitly returned. Wrap the object in parentheses. It would look something like this.

p => ({ foo: 'bar' })

By wrapping the body in parens, the function will return { foo: 'bar }.

Hopefully, that solves your problem. If not, I recently wrote an article about Arrow functions which covers it in more detail. I hope you find it useful. Javascript Arrow Functions

Paul McBride
  • 318
  • 2
  • 9
  • why we don't have to use return keyword inside parenthesis ? – vikramvi Apr 07 '21 at 10:46
  • 1
    Because `p => ({ foo: 'bar' })` is transpiled into `p => { return { foo: 'bar' }; }`. It's a shorthand syntax. – Adrian Wiik Apr 11 '22 at 10:58
  • Arrow functions implicitly return the expression on the right side of the arrow. eg `p => p * 2` will return the result of `p * 2`. The exception to this rule is when the expression on the right side is wrapped in curly braces, then you have to return yourself. – Paul McBride Apr 12 '22 at 11:34
12

Issue:

When you do are doing:

p => {foo: "bar"}

JavaScript interpreter thinks you are opening a multi-statement code block, and in that block, you have to explicitly mention a return statement.

Solution:

If your arrow function expression has a single statement, then you can use the following syntax:

p => ({foo: "bar", attr2: "some value", "attr3": "syntax choices"})

But if you want to have multiple statements then you can use the following syntax:

p => {return {foo: "bar", attr2: "some value", "attr3": "syntax choices"}}

In above example, first set of curly braces opens a multi-statement code block, and the second set of curly braces is for dynamic objects. In multi-statement code block of arrow function, you have to explicitly use return statements

For more details, check Mozilla Docs for JS Arrow Function Expressions

Rusty
  • 4,138
  • 3
  • 37
  • 45
0

ES6 Arrow Function returns an Object

the right ways

  1. normal function return an object

const getUser = user => {
  // do something
  const {name, age} = user;
  return { name, age };
};

const user = { name: "xgqfrms", age: 21 };

console.log(getUser(user));
// {name: "xgqfrms", age: 21}

  1. (js expressions)

const getUser = user => ({ name: user.name, age: user.age });

const user = { name: "xgqfrms", age: 21 };

console.log(getUser(user));
// {name: "xgqfrms", age: 21}

explain

If you were to rewrite this function expression as an arrow function, you might be tempted to simply translate it just like we did in the previous example, like this:

let square = n => {
  square: n * n;
};

When you call square, though, you'll notice the function doesn't work as intended. No matter which input value you pass, you'll get undefined as a return value. Why is that?

The issue with the arrow function is that the parser doesn't interpret the two braces as an object literal, but as a block statement. Within that block statement, the parser sees a label called square which belongs to the expression statement n * n. Since there's no return statement at all, the returned value is always undefined.

To be precise, the body of the function consists of a block statement whose statement list contains a single statement, a labeled statement. Its body is an expression statement holding the binary expression. There's no return statement.

refs

https://github.com/lydiahallie/javascript-questions/issues/220

https://mariusschulz.com/blog/returning-object-literals-from-arrow-functions-in-javascript

xgqfrms
  • 10,077
  • 1
  • 69
  • 68
-8

You can always check this out for more custom solutions:

x => ({}[x.name] = x);