1

The following code worked, and should print the sum of all args:

const s = [5, 7, 2];
const sum = function() {
  return function sum(...args) {
    return args.reduce((a, b) => a + b);
  };
}();

console.log(sum(1, 2, 4, 9)) //prints 16 as expected

The arrow function method that didn't work:

const s = [5, 7, 2];
const sum = () => sum(...args) => args.reduce((a, b) => a + b);
console.log(sum(1, 2, 4, 9))

This result in an error:

SyntaxError: unknown: Unexpected token, expected ";" (4:26) (/index.js:4)

Why does this result in an error?

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 3
    `sum(...args)` - not valid, you need `(...args)` – VLAZ Dec 30 '19 at 20:20
  • 1
    I don't quite understand why the original function has to be an IIFE. Why can't it just be `function sum(...args){ return args.reduce((a,b)=>a+b); }` – nonopolarity Dec 30 '19 at 20:31

2 Answers2

3

Arrow functions can never be named, like you do with

return function sum(

They can be assigned to a variable, like

const fnName = (...args) => ...

in which case the identifier fnName will refer to that arrow function, but the arrow function itself won't (and can't) have a name that becomes an identifier inside the function. In contrast, a full function can have a name, which is what you're doing in the original code with the

return function sum(...args){
//              ^^^

line.

Change

const sum=()=>sum(...args)=>args.reduce((a,b)=>a+b);

to

const sum = (...args) => args.reduce((a, b) => a + b);

const sum = (...args) => args.reduce((a, b) => a + b);
const s = [5, 7, 2];

console.log(sum(1, 2, 4, 9))

With function expressions, the function name usually only really matters when you want to reference the function inside itself, without having a standalone outside variable to refer to, eg:

(function foo() {
  console.log('foo');
  setTimeout(foo, 1000);
})();

This situation is pretty rare, but the technique used above couldn't be done with an arrow function, because arrow functions can't be named - you'd have to save a reference to the function in an identifier first:

const foo = () => {
  console.log('foo');
  setTimeout(foo, 1000);
};
foo();

A function name puts the function's name into the Lexical Environment (scope chain) that the inside of the function can see.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Note that on the right-hand side of assignment expressions, arrow functions *do* get names. https://stackoverflow.com/a/37488652. – Scott Sauyet Dec 30 '19 at 20:27
  • the function that you told me to swap gave the following error: ReferenceError: Cannot access 'sum' before initialization (/index.js:8) – Jhonathan Mizrahi Dec 30 '19 at 20:28
  • @JhonathanMizrahi Your `function` example is creating a function (which is immediately invoked) which returns a function. Not sure what the point of that immediate invocation is - you can either remove it entirely (and just have it be a function of `(...args)`, or if you want the arrow function to also be immediately callable to return a function of `(...args)`, do `const sum = (() => (...args) => args.reduce((a, b) => a + b))();` (but that's quite weird, it doesn't accomplish anything) – CertainPerformance Dec 30 '19 at 20:33
0

The contents of your outer arrow function are this:

sum(...args)=>args.reduce((a,b)=>a+b);

This isn't valid: Arrow function expressions can't be named like function expressions, they can only be assigned to a variable. The interpreter reads the above code as trying to call the outer sum() function and then has no idea what to do with the => following a function call.

Your inner function doesn't need to be named anyway. The original working version has return function sum(...args) { ... } but it would work exactly the same with just return function(...args) { ... }. Since there's no difference, you can simplify the arrow function to this as well:

const sum=(()=>(...args)=>args.reduce((a,b)=>a+b))();

console.log(sum(1,2,4,9));

Note that the function keyword snippet in your question is actually an IIFE, but your arrow function snippet is a function returning a function (sum will return a function instead of a sum): In the stack snippet above I've changed the arrow function implementation to also be an IIFE.

Klaycon
  • 10,599
  • 18
  • 35
  • Note that the original function is actually an IIFE. there is no reason for `sum = () => (...args) => ...`. Instead the equivalent is just `sum = (...args) => ...`. – Scott Sauyet Dec 30 '19 at 20:30
  • 1
    @ScottSauyet Completely missed that. Updated the answer, thanks. – Klaycon Dec 30 '19 at 20:33