7

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
Michel Hua
  • 1,614
  • 2
  • 23
  • 44

3 Answers3

9

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
gil.fernandes
  • 12,978
  • 5
  • 63
  • 76
  • 1
    Related https://stackoverflow.com/questions/9639167/why-doesnt-console-log-work-when-passed-as-a-parameter-to-foreach The answer is a bit different with the evolution of the JavaScript language. – Michel Hua Nov 22 '17 at 14:24
  • *"it is just "unusual" in comparison to Scala or Java (method references) which seem to support method references with one single parameter."* There's nothing about method references in Java that intrinsically limits them to a single argument. This exact situation (`forEach` calling a method that supports varargs) could exist in Java. – T.J. Crowder Nov 23 '17 at 08:06
9

You can use the ES6 'fat' arrow Like this.

     const data = [1,2,3,4]

     data.forEach(item => {
         console.log(item)
     })
Njeru Cyrus
  • 1,753
  • 21
  • 22
1

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).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875