Reputation: 1197
I like to explore the limitations of JavaScript, and wondered if you could use arrow functions where the last expression would be the return statement.
Luckily this is possible, but setting variables in the same scope has some downsides.
[1,2,3,4,5].reduce((sum, element) => (const doubleSum=sum+sum, doubleSum+element));
This returns unidentified identifier (referring to doubleSum)
The solution is to write it like this instead
let doubleSum;
[1,2,3,4,5].reduce((sum, element) => (doubleSum=sum+sum, doubleSum+element));
So now without curly backet i am able to get the sum of sum+sum+element
by having two expressions within the function. This isn't a great example usage, but it shows how to use 2 expressions without curly bracket.
The result of this would be 57
because it only returns doubleSum+element
per iteration. This would work great for calculations if you wanted to split it up into more readable parts.
Another example is to log the results for each iteration without having to use curly brackets
[1,2,3,4,5].reduce((sum, element) => (console.log(sum), sum+sum+element));
//1
//4
//11
//26
//57
I really like this syntax, but i wonder if it is bad practice since it isn't mentioned on Arrow functions
Upvotes: 3
Views: 2084
Reputation: 2913
The ,
you speak of is known as comma operator (MDN entry).
This operator comes from C language where the use-cases were usually one-line declarations of multiple variables (var i, j, k
) and specific macros (which are a pain).
Most modern languages dropped this operator in favor of higher abstractions.
But even if we skipped the history, I would assume that among the primary goals of best practices would be the attribute of readability. There's definitely not a goal of saving a few keystrokes.
Now compare:
let doubleSum;
[1,2,3,4,5].reduce((sum, element) => (doubleSum=sum+sum, doubleSum+element));
and
[1,2,3,4,5].reduce((sum, element) =>
{
const doubleSum = sum + sum;
return doubleSum + element;
});
One of the samples declares doubleSum
as closed-over variable used for all reduce
iterations while the other declares doubleSum
as a variable local to each iteration. Which one do you think shows the intent better? Which one would be easier to refactor without the fear of breaking some odd case?
With the logging example, this is not as clear. However, it is generally considered a good practice to put each side-effect (such as logging a message) into a separate statement (a line ending with ;
).
Imagine this:
someArray.map((element) => (console.log(element), doSomething(element)));
However, for some reason, doSomething
doesn't work the way you expected it to. Let's add some logging:
let intermediate;
someArray.map((element) => (
console.log(element),
intermediate = doSometing(element),
console.log(intermediate),
intermediate));
We're back at that weird scope issue with intermediate
. This change may even not be so easy to do - you want to do something in the map
callback, but in fact you have to create a variable outside its scope to be able to do it. Now imagine that the complexity of the mapping callback would increase to have several such bound variables. Or perhaps to have if/else branches with more variables. And then you'd perhaps like to extract it to a separate function: Now you need to reason about all the bound variables once again.
How about using blocks?
someArray.map((element) =>
{
console.log(element);
doSomething(element);
});
becomes
someArray.map((element) =>
{
console.log(element);
const intermediate = doSometing(element);
console.log(intermediate);
return intermediate;
});
Now, we didn't have to edit anything else than the inner block of map callback - the change was way easier to do and to reason about. Introducing more variables? No problem, they all stay in the callback. Extracting the callback as a separate function? No problem either. The intent of this code is clear.
Upvotes: 2
Reputation: 138267
You cant declare variables inside expressions. But you could build up a function expression and immeadiately call it (called IIFE) so you got local parameters:
[1, 2, 3, 4].reduce((sum, value) => (double => double + value)(sum + sum));
If that is useful is anorher thing.
Upvotes: 1
Reputation: 697
I think what you're trying to achieve might get the code hard to read. There's nothing wrong with using curly braces with arrow function. If you want to keep your reduce callback clean you might want to do something like this:
const doubleSumAndAddElement = (sum, element) => {
console.log(sum);
return 2 * sum + element;
}
[1,2,3,4,5].reduce(doubleSumAndAddElement);
Upvotes: 0
Reputation: 664434
I wonder if it is bad practice
Yes, declaring the doubleSum
outside of the scope of the array function definitely is a bad practice. Don't do that.
Another example is to use
console.log
without curly brackets. I really like this syntax, but it isn't mentioned on Arrow functions
Yes, that's that because it's not specific to arrow functions. You're just using the grouping syntax and the comma operator here. Some similar usage can be found in the Processing and then returning usage example there.
Upvotes: 3