124

Also, is this a style question or a functional question? Is it a matter of preference or is one better? I'm trying to understand the purpose of for-of.

Usually I use,

let iterable = [10, 20, 30];

iterable.forEach((val) => {
   console.log(val);
})

But I see that this new syntax is available.

let iterable = [10, 20, 30];
    
for (let value of iterable) {
   console.log(value);
}

Can one provide an example of a best use case for for-of that might illuminate when one should use it?

Jaydeep
  • 1,686
  • 1
  • 16
  • 29
  • I would not say this is entirely opinion based, since there are definitely some differences between `forEach` and `for/of`. For example, `for/of` can be used to iterate over a generator, where `forEach` cannot. So it is not merely a matter of preference. – CRice Jun 13 '18 at 18:42
  • Some iterables don't have a `forEach()` like a [`FileList`](https://developer.mozilla.org/en-US/docs/Web/API/FileList) for example. Other than iterables that don't implement `forEach()`, it's purely a matter of preference. – Patrick Roberts Jun 13 '18 at 18:43
  • If you don't want to mutate ```value```, you could and should write ```const value of iterable``` – makkabi May 08 '22 at 00:20
  • I think nowadays the question is why one would ever prefer `forEach` over `for..of`. The only practical advantage worth noting (that I can think of) is support for older browsers without transpilation. – General Grievance Aug 03 '22 at 16:09

2 Answers2

150

I recommend to always use for … of in ES6.

  • It works on any iterable
  • It supports all kinds of control flow in the loop body, like continue, break, return, yield and await.

Also I personally find it more readable, but that comes down to preference. Some people think forEach is a more functional style, but that's wrong - it has no result value and is all about doing side effects, so an imperative-looking loop fits that purpose better.

Performance is not a concern, in modern engines all loop styles are equivalent.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    `await` can actually be used within a forEach loop and I'd argue it is actually easier. With `for-of` you have to wrap the whole thing in an async function. With `forEach` you can just make the callback async: `[1,2,3].forEach(async (value) => {await new Promise(resolve=>console.log(value))})` – Forivin Jan 20 '19 at 13:18
  • 33
    @Forivin [That doesn't work](https://stackoverflow.com/q/37576685/1048572), the loop will not be waited for. Your code is equivalent to just creating the promise and not using `async`/`await` at all. – Bergi Jan 20 '19 at 13:21
  • Well, it does work, the use-case is just different and admittedly unusual. But the promise executors will be in fact be called. – Forivin Jan 20 '19 at 14:08
  • 19
    Well for the different use case you don't need `await` at all, and so you could just write `for (const value of [1,2,3]) { new Promise(resolve => console.log(value)); }` – Bergi Jan 20 '19 at 14:11
  • @Forivin You can do it using Array methods with `Promise.all` as long as you return an Array - so just use `map` instead of `forEach` as in: `await Promise.all([1, 2, 3].map(async value => { const result = await foo(value); }))` this would await each async handler without having to use `for..of`. – Benny Schmidt Mar 27 '23 at 16:03
  • @Forivin no it doesn't work, yes it will be called, but the point is it won't be awaited, there are Promise.all/allSettled api for that – Zaya Aug 30 '23 at 07:58
58

This is a very interesting question which has been discussed in many other sites. I'll post the basics of what I have read.

ForEach exclusively belong to the royal family of Arrays. The forEach method was introduced with lineage to the prototypal inheritance of Array object! Needless to say, the forEach clause works only with those data structure which are Arrays. The method basically iterates over the elements of the array and executes a callback function [basically some executable function/ fun activity].


The for-of loop is adequately new to the JS world and packs in super-powers! Voilaaaaaaa! The for-of loop creates a loop iterating over iterable member objects. The list is an extensive one such as

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • Other W3C classes

You need to know that this bad-ass boy emerged with the birth of ES6 in 2015. So, it offers plenty of flexibility in usage


Performance

In performance, for...of is faster than forEach. Results can be found here

forEach is 24% slower than for...of


Update

There are several other iterable classes in the W3C specification, like FileList, as I mentioned above. And in recent drafts of W3C (around when ES6 was released), collections like HTMLCollection and NodeList now implement forEach() as well, not just Array anymore. By @Patrick Roberts


Source Links:

Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
  • 4
    That list only mentions classes in the ECMAScript specification. There are several other iterable classes in the W3C specification, like `FileList`, as I mentioned above. And in recent drafts of W3C (around when ES6 was released), collections like `HTMLCollection` and `NodeList` now implement `forEach()` as well, not just `Array` anymore. – Patrick Roberts Jun 13 '18 at 18:46
  • 6
    In latest firefox, `forEach` is faster than `for of`, but in chrome, `for of` is faster. – Sphinx Jun 13 '18 at 19:04
  • Intersting. It seems that depends on the browser javascript engine. Mozilla uses SpiderMonkey while Chrome uses Chrome v8. Maybe the implementation of `forEach` and `for...of` is different. – Luis felipe De jesus Munoz Jun 13 '18 at 19:07
  • 2
    Unless there's a fundamental reason why some constructs are much harder to optimize for, these kinds of benchmark comparisons are brittle. For example, on the most recent v8 version 10.4.123.20 I'm finding that `for...of`, `for`, and `forEach` basically have the same performance. – Meow Aug 09 '22 at 17:29
  • You had me at "super-powers!" "Voilaaaaaaa" and "bad-ass." – Big McLargeHuge Sep 25 '22 at 16:03
  • "In performance, for...of is faster than forEach" **Never** make such general statements. Performace depends on so many factors and mostly is irrelevant when your code doesn't do what it is suposed to do or when it's impossible to maintain because of over-optimzation. – MakePeaceGreatAgain Apr 24 '23 at 08:19