3

With for..of introduced in ECMAScript 2015 (ES6), is there any reason to continue advocating use of the slightly older Array.prototype.forEach()?

A lot of code written in ES6 today contains code such as:

let sum = 0;
values.forEach((value) => {
    sum += value;
});

In almost all of these situations, an equivalent for..of loop could be used instead:

let sum = 0;
for (let value of values) {
  sum += value;
}

The more concise versions of the two formats:

values.forEach(value => sum += value);
for (let value of values) sum += value;

The for..of format works not only with Array objects but other iterables as well and is more performant. Unlike Array.prototype.map() there is also no return value to .forEach() that would allow for further chaining.

It could conceivably be more readable and therefore useful at the end of a call chain (example below), or if each item should be applied to an unknown callback. Those edge cases aside, should it not be avoided?

['1', '2', 3].map(Number)
             .forEach(value => sum += value)
lyschoening
  • 18,170
  • 11
  • 44
  • 54
  • @Rooster Since `for...of` is an ES6 feature, questionable browsers don't support either of these options. – ssube Jul 10 '15 at 15:28
  • `for of` and `forEach` are about the same thing for the average coder. On the other hand, as usual, no IE support for the `for of` and `for in` loops so I'd avoid those for a while. – ODelibalta Jul 10 '15 at 15:28
  • @ssube he asked is there ANY reason, not is there any reason for things that support ecmascript6 :) Granted, I guess your point may be somewhat implied ;P – Rooster Jul 10 '15 at 15:30
  • 1
    I hardly found any use cases for `forEach` so far (you know, side effects are bad), and it certainly won't be any more useful in ES6. – Bergi Jul 17 '15 at 14:23

1 Answers1

5

The most important difference is that you cannot break from a forEach without throwing, which is using exceptions for flow control and therefore bad practice.

For an array loop that will always touch every element, for ... of and forEach are pretty equivalent. However, if you have a loop that is guaranteed to hit every element once, you can probably use map or reduce in place of any for-each construct and make things More Functional.

Your sum example is a great one for reduce. forEach is not the best choice, when you can just use:

let sum = values.reduce((sum, value) => sum + value, 0);

If you want to pick elements out of an array, you can typically use filter. For flow control, every and some work, with inversion as necessary (as mentioned in the comments).

In general, forEach can usually be replaced by a more descriptive and specialized array method, unless you specifically need to cause side effects. for...of is very useful with iterable objects, but not always the best choice for arrays.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
ssube
  • 47,010
  • 7
  • 103
  • 140
  • Probably not the best choice of example from my side. You are of course right in pointing out that `reduce()` should be used here. – lyschoening Jul 10 '15 at 15:33
  • 1
    For flow control, `.every()` or `.some()` could be used. – lyschoening Jul 10 '15 at 15:37
  • 1
    @lyschoening: No, it really shouldn't. If you need custom control flow, use a loop and `break` explicitly. Please don't abuse `every` or `some`. – Bergi Jul 17 '15 at 14:20
  • @Bergi The documentation for [.forEach() on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description) suggests using them for that purpose, that's why I mentioned here as an alternative to throwing an error to break the loop. It's not something I could ever see myself writing. – lyschoening Jul 17 '15 at 14:28
  • @Bergi while you're right that breaking can be better for complex flow, I think every or some as the condition to an if is a very valid use case. – ssube Jul 21 '15 at 04:22
  • @ssube: I didn't mean to suggest otherwise :-) But I don't consider using `every`/`some` in a condition to be "flow control" (of the loop) – Bergi Jul 21 '15 at 14:40