0

This snippet of JavaScript code alerts 1 as answer. Can anyone please explain how this code executes?

const b = [1,2,3];
const f = (a, ...b) => a+b;

alert( f( 1 ) );
Dai
  • 141,631
  • 28
  • 261
  • 374
  • 2
    What else would you have expected? You might want to log the value of `b` inside the function `f`. – Bergi Aug 19 '18 at 15:58
  • 1
    The `b` on the `const f = ` line represents a new parameter in the lambda's scope, it does not refer to the `[1,2,3]` array declared in the parent scope. When `f(1)` is invoked it does not bind a value to the variadic parameter `b` so its value is an empty array and `1 + [] === "1"` in Javascript, hence your output value. – Dai Aug 19 '18 at 16:01
  • Also note that `...` isn't an operator (neither when used for spread or, as above, for rest). And can't be, operators can't do what either spread or rest do. – T.J. Crowder Aug 19 '18 at 16:02
  • 1
    See https://stackoverflow.com/a/44934830/5647260 in regards to TJ's comment. – Andrew Li Aug 19 '18 at 16:08

5 Answers5

4

There are a couple of things going on here. The main one is that you're shadowing b, so the b outside the function isn't used within it. Instead, within it, you're creating a new array (because you've used a rest parameter, ...b) and assigning it to the b parameter. Since you call f with just one parameter, that array is empty. 1+[] is "1" because when either of the operands to + isn't a primitive (arrays aren't primitives), it's coerced to a primitive, and coercing an array to a primitive (indirectly) results in doing a .join(",") on the array. With a blank array, .join(",") is "". Then, since one of the operands is a string, the other operand (1) is coerced to string ("1") and it does "1"+"" which is, of course, "1". (Details on that last bit in the spec.)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • @Li357 - Fixed it, thanks for flagging that up. It's because ToPrimitive is used without any hint, and the default for arrays is number, but ToPrimitive on an array with hint number tries `valueOf` and then `toString`. Array's `valueOf` returns the array, which isn't primitive, so `toString` is used instead: https://tc39.github.io/ecma262/#sec-toprimitive – T.J. Crowder Aug 19 '18 at 16:08
  • Thanks for the follow up! – Andrew Li Aug 19 '18 at 17:25
0

f(1) is the same as 1 + []

f(1,2,3) is the same as 1 + [2, 3]

That's all...

The first line const b = [1,2,3]; is not used because the b in the lambda expression is the argument, not the constant declared before.

Maxime Chéramy
  • 17,761
  • 8
  • 54
  • 75
0

You can reference variables in a function call, however, when you define a function expression, the parameters name do not refer to any variables.

You'll get the expected result if you call the function like this:

alert(f(1, b));
Vgoose
  • 249
  • 1
  • 10
  • *"You'll get the expected result if you call the function like this:"* Well, I don't think the OP has ever answered the question of what he/she expects. But note that if you just change the call as you suggest, `b` within `f` will be `[[1, 2, 3]]` (note that's an array inside an array), and the result would be `"11,2,3"` which I doubt very much is what the OP is expecting. – T.J. Crowder Aug 19 '18 at 16:14
0

It takes the rest parameters ... as an array b.

While this is empty, it is converted to an empty string and both operands are treated as string, because if one is a string, then it adds all values as string.

The result is '1'.

const b = [1, 2, 3];
const f = (a, ...b) => a + '';

console.log(typeof f(1));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Reproducing this in my browser's development tools console looks like this:

> b = [1,2,3]
> f = (a, ...b) => a+b
> f(1)
< "1"
// so it results in the string 1, why's that?
// lets try logging what a and b are in the function
> g = (a, ...b) => console.log("a=%o, b=%o", a, b)
> g(1)
< a=1, b=[]
// ah, so b is an array, which is what the spread operator does 
// (gathers all remaining arguments into an array, so the question 
// is then what does JavaScript return for the number 1 added to an empty array?
> 1 + []
< "1"

This behavior is one of the many quirks of JavaScript when using the + operator on different types.

Kyle Burton
  • 26,788
  • 9
  • 50
  • 60