◆ for-of 使わないようにする人がいるらしい
◆ 全部配列化して forEach にするほうがありえないよね

ネットできいた噂なので詳しいことはしらないのですが for-of は使わない主義の人がいるとか

私も for-in の頃は for-in がダメすぎてすべて map/reduce/filter/forEach などで処理する派でしたが ES2015 を使い始めてからはループ処理は for-of がメインです
ES2015 が出てから数年たった今で for-of なしで全部 forEach とか考えられません
for-in のことを書いてる昔の記事を見て for-of と思って広がったんじゃないのかと思うほどです

イテラブルなものならなんでも使える

forEach は配列限定なので

[...document.images].forEach(img => console.log(img.src))

みたいな変換が必要です

for-of は iterable なものなら何でも良いので

for(const item of [1, 2, 3]){}
for(const item of new Set([1, 2, 3])){}
for(const item of new Map([[1, 2], [2, 3]])){}
for(const item of document.images){}
for(const item of arguments){}
for(const item of function*(){yield 1}()){}

などの書き方ができます
変換不要です

無限に続く generator

特に generator の場合は配列変換すると無限なものが扱えません

function* fib(){
const a = [0, 1]
while(true){
a.push(a[0] + a[1])
yield a.shift()
}
}

for(const item of fib()){
if(item < 1000) console.log(item)
else break
}

フィボナッチ数を 1000 まで表示するものですが generator 側は終わりが無いので [...fib()] なんてしたら無限ループです

scope

昔は forEach が良かった理由はスコープがあることです
関数スコープなのでコールバック関数として関数を渡して実行してもらうことでそれぞれにスコープが作られました
こうすればループ変数は固定なのでループの中で毎回関数を作って listener に設定しても実行時にループ変数が変わることがありません
個々にスコープが作られないループで 関数に bind したりせず単純に参照していたりすると関数が呼び出された時に 全部同じループ変数ということあります

今では let/const でスコープが作れます
なので繰り返しのようなところでわざわざコストの高い関数呼び出しをしなくて良いです

とは言ってもメリットがないのに関数呼び出しするのは避けたら良いくらいで 複数箇所のループで共通な処理だから forEach に同じ関数を渡すとか map や filter みたいな処理をするときには for-of を使わなくて良いと思います
map や filter はどういう用途のループなのかがメソッド名からわかりますが全部 for-of になっていたらちゃんと読まないと意図が分かりづらいです

map や filter などでなく単純な forEach でその場限りでやるようなことは for-of でやればいいと思います

こう考えると C# の LINQ で ForEach だけなくて自分で作っていましたが必要なかったんだなと感じられました

工夫すると便利

ところで普通の i をインクリメントしていくタイプの for も for-of にできる場合が多いです
N 回実行したいなら

for(const _ of Array(10)){
console.log(".")
}

今何回目か知りたいなら

for(const i of Array(10).keys()){
console.log(i)
}

配列のインデックスとバリューの両方がほしいなら

for(const [index, value] of ["a", "b", "c"].entries()){
console.log(index, value)
}


Object.entries([]) にするとキーが文字列扱いになります
配列のメソッドにするとインデックスの数値型として受け取れます
オブジェクトの場合は Object.entries を使えばキーとバリューが受け取れます