Signifigance of "a+b, 0"

https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/es6/use-the-rest-operator-with-function-parameters

In particular

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

why is the ,0 needed? I changed the code to

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

or

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

The modifications I made gave the exact same result as the original one as given in the challenge.

Can someone please explain if the ,0 is necessary and what type of situations it would be used for?

Just some feedback - these ES6 challenges are lacking any explanation of .map, .reduce and .fliter which has personally caused me a lot of ‘‘inefficent’’ learning, I’m not sure if it is just me. FCC is excellent just some honest feedback.

It isn’t strictly needed, but it sets the initial accumulator value to zero. Kind of a nice way to ensure expected behavior.

1 Like

The reason it’s needed is that sometimes, you’ll be receiving arrays of length 0 or 1. In these cases, special, and perhaps unexpected, things happen.

Empty array

Let’s say you have an empty array.

[].reduce((a, b) => a + b)

It does not know what to do. It doesn’t know what to set a and b to. It throws an error – and that’s not good.

[].reduce((a, b) => a + b, 19)

This code, however, will result in no error – and will return 19, the default value.

Array of length 1

Now, let’s take a look at another example.

[4].reduce((a, b) => 10)

What does that output? Well, because the array only contains one element, and there’s no default value, reduce will just return that element. So the return value is 4, not 10. This seems silly. Had any more values in the array, we would’ve reduced to 10 – it’s just a weird result.

So, let’s add a default value.

[4].reduce((a, b) => 10, "lol")

This results in 10. Why? Because JavaScript could now determine the value of both a and b. a was set to 4, and b was set to "lol". Hence, the function was called and its return value (10) was used.

Why it worked in your case

So what happened?

Not providing an initial value is legal – it’s an optional value after all. And if you do this, initialValue becomes the first element in the array (and the first element is skipped, so you don’t get two identical arguments).

As demonstrated above, this is totally cool… until your array has no elements, and an error is thrown; or one element – where in this case it wouldn’t matter (the sum of a single element is the element itself). But in other cases it would, and therefore it’s a good practice to stick to.

But also, note that had you done this:

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

Then your function would output NaN (except when there’s no elements, then it’s undefined). Why? Because undefined + 5 (or any number for that matter) is NaN.

Hence, if you’re going to set it, you must ensure you’re setting it to the correct value. And you definitely should, people will pass empty arrays, because people are annoying. :wink:

3 Likes

Excellent answers, thank you both so much!

I am currently practising changing from writing functions in the ‘‘normal’’ way to the arrow style as per ES6.

In the interests of not making too many topics, I hope it’s fine if I quickly check this here. Also, this code I’m changing will still relate to the same challenge.

My attempt to change the code given in the challenge is this:

const sum = () => sum (x,y,z) => const args = [x , y , z]; args.reduce((a,b)) => a+b,0;

Any feedback please? I like how it’s written, it just gets tricky when you try to do it with functions inside functions and I know this is clearly wrong for reasons unknown to me. Or is it that in some circs, you cannot use => like this?

That won’t run, I’m afraid it’s not valid JavaScript. Try writing it with normal anonymous function syntax, and then rewriting into arrow functions (you aren’t doing anything sneaky with this, so this is fine to do.) :slightly_smiling_face:


const sum =  ( () => sum = (x,y,z) => {const args = [x , y , z]; return args.reduce((a,b) => a+b,0)} )

… Is this it?

I mean… try running it :stuck_out_tongue:

() => sum = (x, y, z) =>

What are you trying to do here? Are you trying to create a higher-order-function… if so, why do you assign to sum? I’m a little confused as to what your code is trying to do — could you tell me?

The purpose / aim is to make it do exactly the same thing as the code in the challenge i.e.

const sum = (function() {
  "use strict";
  return function sum(x,y,z) {
    const args = [ x, y, z ];
    return args.reduce((a, b) => a + b, 0);
  };
}

Hope that clarifies what I’m looking for?

Ah, alright!

() => body

is shorthand for

() => { return body }

So trying to use the shorthand for multiple lines/const will not work so well. Note that their use of a closure is super weird, and is just confusing the situation. Note that the inner function need not be called sum for the code to work, and really… you shouldn’t need to use a closure at all. Ideally, you could just write

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

(And the 0 is used in case an empty set of arguments is provided).

I’m not sure why FCC didn’t use one line.

Thank you so much for the effort of explaining this all. Yes good point, i think there being another function inside another function which literally doesn’t do anything has me confused a lot. I think the challenge should be

sum = ( function(x,y,z) {
const args = [x,y,z];
return args.reduce( (a,b) => a+b,0 );
}

Please tell me that in real terms, what I’ve just wrote is the same thing and I’m not just going crazy??

Okay so for

() = > a + b

will return the value of a + b

whilst

() => { const a = 7; var b = 7; var array = [5,6,7] }

will NOT return anything, anything inside the { } is similar to the below:

function sum () {
var a = 6;
var b = 33;
let array = [4,5,6]
}

Is this understanding correct…?

Yep, you’re spot on! You can do () => { return 5 } if you want to return from a {}

1 Like

You are a legend, thank you, your abilities at such a young age has me astounded! :open_mouth:* Sends positive rep*

1 Like

:tada:

For reference, lodged in the GitHub issue tracker as #295