Arrow function return and double curly brackets

Hello,
If I well understood, for this code:

const getMousePosition = (x, y) => ({ x, y });

If I want to use “return” I have to replace parenthesis by curly brackets.

const getMousePosition = (x, y) => {return { x, y }};

If it’s true, why this is not explain inside the lesson.
https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/es6/write-concise-object-literal-declarations-using-object-property-shorthand

This is not valid.

This is correct.

In order to use the implit return with an object, you need to use ()s.

If you want to use double {}s, then you must use the return keyword.

Hi Jeremy,
I made a modification in my first post compared to the solution:

const getMousePosition = (x, y) => {return { x, y }};
const createPerson = (name, age, gender) => {
  "use strict";
  // change code below this line
  return {
    name,
    age,
    gender
  };
  // change code above this line
};

There are a gazillion things that can’t be covered in the FCC materials - there just isn’t room. I don’t know if this is explained anywhere - I don’t have everything memorized.

I used to kid the junior devs at my last job, I used to ask them little “trivia” questions. One was this:

What does the function () => {} return.

You would be amazed how many confidently said, “an empty object”. Nope. In JS, if you start a statement with {, JS will assume that it is a code block.

So, for this:

(x, y) => { x, y };

JS would see that as a codeblock. In that it sees two expressions (x and y) separated by the comma operator. It evaluates each (which do nothing) and there is no return statement so it returns nothing. You can use the parentheses to tell it, “this is not a code block, these is an inline object literation and since there is no codeblock, I want you to return that.”

(x, y) => ({ x, y });

That is why this:

() => {};

Returns undefined. (It is an empty code block with nothing in it, not even a return.) If you want an empty object, you would need:

() => ({});
4 Likes

curly brackets expanding the arrow callback one line to multiline where you need to use return statement to get back any value. If you still want use one line return then the return statement have to be ommited and curly brackets have to be covered by parentheses.

1 Like

I all understood with this post.

“curly brackets expanding the arrow callback one line to multiline where you need to use return statement to get back any value. If you still want use one line return then the return statement have to be ommited and curly brackets have to be covered by parentheses.”

But Reaz, just for check, your last explanation is about this syntax. Are you ok ?

const getMousePosition = (x, y) => {return { x, y }};

It reminds me of another similar issue with destructuring an object to a variable that is declared previously. Consider:

const obj = { prop1: '111', prop2: '222' };

const { prop1 } = obj;
console.log(prop1);
// 111

let prop2
// { prop1 } = obj; // doesn't work, throws an error
({ prop2 } = obj);
console.log(prop2);
// 222

The first desctucturing makes sense.

For the second one, the variable prop2 is declared above so not at the time of the descructuring. You would expect to be able to do this:

{ prop1 } = obj;

You can’t do that for the same reason as your arrow function - you can’t start an expression with a { of JS assumes that it is a code block. So JS evaluates the code block, gets to the = and has no idea what the heck is going on. So, you wrap the destructuring in parentheses and it works:

({ prop2 } = obj);

I actually ran into that problem once at work. I figured out (probably found it on Stack Overflow or some blog), but the guy reviewing the code asked me to get rid of the parentheses for being unnecessary. I had to explain that they were necessary and why. It works, but it looks weird, until you understand what is going on.

Of course, arrays don’t present the same problem because JS know when it sees a [ that it is an array. But { can mean a few different things.

1 Like

Kevin,
ok but compared to the code below I still do not see in which case we are.

const createPerson = (name, age, gender) => {
  "use strict";
  // change code below this line
  return {
    name,
    age,
    gender
  };
  // change code above this line
};

for me it is necessary to add this syntax:

const getMousePosition = (x, y) => {return { x, y }};

This:

const createPerson = (name, age, gender) => {
  "use strict";
  // change code below this line
  return {
    name,
    age,
    gender
  };
  // change code above this line
};

is an arrow function with a code block and an explicit return. It could be rewritten as:

const createPerson = (name, age, gender) =>({
    name,
    age,
    gender,
});

or

const createPerson = (name, age, gender) => ({ name, age, gender });

Note that these last two examples are not code blocks and are using an implicit return. All three of these do the same thing. Note that for the implicit return ones, since we are returning an object literal, we need to wrap them in parentheses.


This:

const getMousePosition = (x, y) => {return { x, y }};

is also a code block with an explicit return. Just like the last one, we can rewrite it with and explicit return and no code block:

const getMousePosition = (x, y) => ({ x, y });

They work exactly the same, and again we need the parentheses for the same reason.

Note that this is mainly an issue with objects, because of the ambiguity of the { - when in doubt, JS will assume it is the opening of a code block, not an object literal.

OK, but I find that it is really not good to have given as a solution the syntax with double curly bracket. This does not correspond to the example given in the lesson.
But I understood the difference now and thanks to your explanations. thank you.

As a counter example, here:

const adder = (x, y) => x + y;

That does NOT need parentheses around the implicit return because there is no { so there is no confusion about what it is - JS knows that this is an expression to be evaluated and returned. You could add parentheses:

const adder = (x, y) => (x + y);

but it is not necessary. In theory you could have a bunch:

const adder = (x, y) => (((((x + y)))));

in this case they don’t really do anything because they aren’t clearing up an order of operations problem.

Which solution is this?

Kevin,
Yes, I understand.
Thanks again.

If this is what you mean by “double curly bracked”:

(x, y) => {return { x, y }};

They are serving two functions. The outer curly braces are defining a code block and the inner curly braces are defining an object literal.

Why use the same symbol? You’d have to ask the elders of JS, but I imagine it is because those are symbols that got inherited from C and other languages.

I think it is more useful to understand the difference so you can tell the difference rather than kvetch about the confusion. Once you understand the difference, there is no confusion.

I’m not saying this to put you down - I had the same confusion when I was where you are. I imagine that most people do.

2 Likes

Yes, well done. This is the sentence that sums it all. :wink:

1 Like

Hello kevin,
One more thing for ending
Thus I can’t write this code:

 item => ( {  `<li class="text-warning">${item}</li>`
                         `<li class="other-class">${item}</li>`
                  } );

Because it’s not a Object ?

What does that mean? You have two template literals in a row. This doesn’t work either:

console.log(`Howdy` ` pardner!`);

That is not how we concatenate strings.

 item => ( {  `<li class="text-warning">${item}</li>`
                         `<li class="other-class">${item}</li>`
                  } );

No, this is “not an Object”. It is like you are trying to return an object, but what are the keys and values? It’s not a properly formed object. What are the keys? I mean, in theory you could do something like:

const foo = item => ({'<li class="text-warning">${item}</li>': `<li class="other-class">${item}</li>`} );

but that is not the result you want.

Before understanding if you can do something, please clarify what your expected result is.

Sorry kevin, my post was awkward.

It’s because Reaz said upper:
“curly brackets expanding the arrow callback one line to multiline where you need to use return statement to get back any value. If you still want use one line return then the return statement have to be ommited and curly brackets have to be covered by parentheses.”

(I’m not sure about “any value”. )

And as you said:
"You can use the parentheses to tell it, “this is not a code block, these is an inline object literation and since there is no codeblock, I want you to return that.”

My question is in this case where there is only one line with parentheses:
(x, y) => ({ x, y });

Is it true if I say that { x, y } is inevitably/ obligatorily an object and never 2 intructions( codeblock) ?

From that you said it seem it’s clear that is an objet. But when I read what Reaz says I’m not sure anymore.

A one liner (not a code block) is just that - one line of code and whatever it evaluates to is what it returns.

const foo = param => bar(param);

When foo is called, it will pass param to bar and whatever bar returns, it will pass through and be what foo returns. This is functionally equivalent to this:

const foo = param => {
  const returnValue = bar(param);
  return returnValue;
};

which in roughly equivalent to:

function foo(param) {
  const returnValue = bar(param);
  return returnValue;
}

Or of course in the last two examples:

  const returnValue = bar(param);
  return returnValue;

could be simplified to:

  return bar(param);

That is it. That is the difference. There are technically a few other small differences between an arrow function and a standard function, but it doesn’t matter in this example.

Is it true if I say that { x, y } is inevitably/ obligatorily an object and never 2 intructions( codeblock) ?

It depends what you want. This:

const foo = (x, y) => { x, y };

is perfectly valid JS, it just doesn’t do what you want. This is the same as:

const foo = (x, y) => {
  x, y;
};

If I call it with foo(1, 2);, then it is equivalent to this:

const foo = () => {
  1, 2;
};

Since the comma operator evaluates the expressions and uses the last one, it is the equivalent to this:

const foo = () => {
  2;
};

You are not doing anything with that expression - you are not returning it, you are not using it in another expression, you are not assigning it to a variable. It is just an expression in the middle of nowhere that gets lost because we are not using it. It is a tree falling in the forest where there is no one there to hear it. It gets lost forever. And since we are not returning anything, the function does nothing and returns undefined.

From that you said it seem it’s clear that is an objet. But when I read what Reaz says I’m not sure anymore.

This does nothing but returns an object:

const foo = (x, y) => ({ x, y });

This does nothing and returns nothing:

const foo = (x, y) => { x, y };

As far as what Raez said:

… curly brackets expanding the arrow callback one line to multiline where you need to use return statement to get back any value.

That is consistent with what I am saying. Curly braces will make it a code block so you can have more than one line of code.

If you still want use one line return then the return statement have to be ommited …

Yes, I agree with that. If you want to have one line, then omit the curly braces so it knows that it is not a code block and you don’t need a return - whatever that expression/statement evaluates to will be the return value.

… and curly brackets have to be covered by parentheses.

In the context of “wanting to return an object”, yes, that is correct. If you weren’t returning an object it wouldn’t matter:

const sum = (x, y) => x + y;

It is not needed there because the is no ambiguity. But if you are trying to return an object with the one line, implicit return, when JS sees that { it cannot tell if you are defining an object literal or if you are starting a code block. It will assume you are making a code block. If you want to tell it that you are writing an object literal, then do as Raez says and wrap it in parentheses.