forEach loop on array with fat arrow

Viewed 11961

I would like to print an array line by line with carriage return.

Simple implementation is [1,2,3].forEach(function(x) {console.log(x)}) to get this as output

1
2
3

Now if I use the syntactic sugar of ES6 fat arrows,

michel$ node
> [1,2,3].forEach(x => console.log(x))
1
2
3
undefined
>
> [1,2,3].forEach(console.log)
1 0 [ 1, 2, 3 ]
2 1 [ 1, 2, 3 ]
3 2 [ 1, 2, 3 ]
undefined

When omitting the function parameter in the forEach callback, it looks like the second version is returning a cartesian product of itself.

In other functional languages like Scala this is totally ok, why is this "wrong" in JavaScript?

michel$ scala
scala> Array(1,2,3).foreach(x => println(x))
1
2
3

scala> Array(1,2,3).foreach(println)
1
2
3
3 Answers

It seems that this code here:

[1,2,3].forEach(console.log)

is the same as:

[1,2,3].forEach((value, index, array) => console.log(value, index, array))

It is not "wrong", it is just "unusual" in comparison to Scala or Java (method references) which seem to support method references with one single parameter. Javascript just seem to copy all parameters across to the referenced method (e.g. console.log) and if this method supports varargs, everything gets processed.

But if you do not like this behaviour you can fix it in Javascript. Create a simple function which accepts one single parameter:

function print(t) { console.log(t) }

and then execute:

[1,2,3].forEach(print)

And this prints the result, that will let you feel at home if you are coming from a Scala background:

1
2
3

forEach passes multiple arguments to the callback, not just one: The item, its index, and the object on which forEach was called. Most implementations of console.log accept multiple parameters and output all of them. That's why forEach(console.log) outputs the entry (1), its index (0), and the array ([ 1, 2, 3 ]), then the next, etc.

With the arrow function, you're only using the first of those arguments.


Side note: forEach(console.log) also passes in console.log without ensuring that this during the call to log will be console. Some console implementations don't care, others do. So if you wanted that second form, you'd probably be better off with forEach(console.log, console).

Related