我正在阅读airbnb javascript guide。有一个特别的陈述,说:
不要使用迭代器。更喜欢JavaScript的高阶函数,而不是像for-in或for-of那样的循环。
他们给出上述陈述的原因是:
这会强制执行我们的不可变规则。处理返回值的纯函数比副作用更容易推理。
我无法区分给出的两种编码方法:
const numbers = [1, 2, 3, 4, 5];
// bad
let sum = 0;
for (let num of numbers) {
sum += num;
}
sum === 15;
// good
let sum = 0;
numbers.forEach((num) => {
sum += num;
});
sum === 15;
有人可以解释一下,为什么forEach
优先于常规for
循环?它如何真正有所作为?使用常规iterators
是否有任何副作用?
答案 0 :(得分:4)
这没有任何意义。永远不应该首选forEach
。是的,使用map
和reduce
以及filter
比使用副作用操纵某些内容的循环更清晰。
但是当您因某种原因需要使用副作用时,for … in
和for … of
是惯用的循环结构。它们更容易阅读和just as fast,并强调你有一个带有副作用的循环体,与forEach
形成鲜明对比,它看起来与回调有关,但却没有。与forEach
相比的其他优点包括您可以对迭代元素使用const
,并且可以使用任意控制结构(return
,break
,continue
,{{ 3}},yield
)在循环体中。
答案 1 :(得分:4)
Airbnb样式指南中的这种推理适用于用于不变性的数组方法,filter
,map
,reduce
等,但不是forEach
:< / p>
这会强制执行我们的不可变规则。处理返回值的纯函数比副作用更容易推理。
所以比较更像是:
// bad
let sum = 0;
for (let num of numbers) {
sum += num;
}
sum === 15;
// bad
let sum = 0;
numbers.forEach((num) => {
sum += num;
});
sum === 15;
// good
const sum = numbers.reduce((num, sum) => sum += num, 0);
sum === 15;
一般来说,for > forEach > for..of > for..in
就性能而言。这种关系几乎在所有引擎中都是一致的,但可能因阵列长度不同而不同。
forEach
是在最新Chrome / V8中得到显着改进的版本(几乎两倍,基于this综合测试):
由于所有这些都很快,因为性能原因选择不太合适的循环方法可以被认为是初步优化,除非另有证明。
与forEach
相比,for..of
的主要好处是,前者即使在ES3中也可以填充并提供值和索引,而后者更易读,但应在ES5及更低版本中进行转换
forEach
已知存在一些陷阱,使其无法在某些可以使用for
或for..of
正确处理的情况下使用:
回调函数创建新的上下文(可以使用箭头函数解决)
不支持迭代器
不支持生成器yield
和async..await
没有提供使用break
提早终止循环的正确方法
答案 2 :(得分:1)
大多数时候,Airbnb风格指南试图保持一致。这并不意味着永远不会有使用for循环或for-in循环的理由,比如假设你想要提前摆脱循环。
当使用for循环来改变某些东西的价值时,不变性就会发挥作用。就像将数组缩减为整数或映射元素以生成新数组一样。使用内置的map
,reduce
或filter
,不会直接改变数组的值,因此它是首选的。在for / for-in循环上使用forEach
强制了在迭代器上使用更高阶函数的样式一致性,因此我认为这就是为什么它被推荐。
答案 3 :(得分:0)
以下是我在两者之间看到的优势列表。
forEach
,您需要更改您所在的堆栈条目,以查看循环函数中未访问的变量)break
或continue
,而不需要使用some
函数并执行return true
,这会降低可读性。 (可以为emulated)await
,并保留async / await上下文。 (可以为emulated)map
和filter
之类的函数调用,因此在两者之间进行转换更容易。break
,continue
,return
甚至async
/ await
的支持的版本)for-of
,{const
多5个字符;如果使用let
/ var
,则多3个字符)答案 4 :(得分:0)
forEach
迭代不能被await
延迟。这意味着您不能使用forEach
来管道传输Web请求到服务器。
forEach
上也没有async Iterables
。
请考虑以下情况:
let delayed = (value)=>new Promise(resolve => setTimeout(() => resolve(value), 2000));
(async ()=>{
for(el of ['d','e','f'])console.log(await delayed(el))
})();
(async()=>{
['a','b','c'].forEach(async (el)=>console.log(await delayed(el)))
})();
结果:
d
a
b
c
e
f
每两秒钟打印一次[d,e,f]
数组的元素。
[a,b,c]
数组的元素在两秒钟后全部一起打印。
let delayed = (value)=>new Promise(resolve => setTimeout(() => resolve(value), 2000));
async function* toDelayedIterable(array) {
for(a of array)yield (await delayed(a))
}
for await(el of toDelayedIterable(['d','e','f']))console.log(el)
toDelayedIterable(['a', 'b', 'c']).forEach(async(el)=>console.log(await el));
结果:
d
e
f
Uncaught TypeError: toDelayedIterable(...).forEach is not a function
[d,e,f]
数组的元素每两秒钟打印一次。
尝试访问forEach
的{{1}}数组上的asyncIterator
时出错。
答案 5 :(得分:-1)
请参阅the tooltip for area此处
仅用于readablity我们正在使用foreach。 除了for循环之外,首选浏览器的兼容性,性能和原生感。