Heim > Artikel > Web-Frontend > Der Unterschied zwischen den vier Array-Traversal-Methoden in JS ( for , forEach() , for/in, for/of)
Wir haben mehrere Möglichkeiten, Arrays oder Objekte in JavaScript zu durchlaufen, und die Unterschiede zwischen ihnen sind sehr verwirrend. Airbnb-Codierungsstilfor/in und for/of sind verboten, wissen Sie warum?
In diesem Artikel werden die Unterschiede zwischen den folgenden vier Schleifensyntaxen ausführlich vorgestellt:for (let i = 0; i b54a68934332789439408db30e7fdc2f { /* ... */ })
for (let i = 0; i 94ffee46481db95b32f32d90a564f64d { /* ... */ })
for (let i in arr)
for (const v of arr)
使用for
和for/in
,我们可以访问数组的下标,而不是实际的数组元素值:
for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); } for (let i in arr) { console.log(arr[i]); }
使用for/of
,则可以直接访问数组的元素值:
for (const v of arr) { console.log(v); }
使用forEach()
,则可以同时访问数组的下标与元素值:
arr.forEach((v, i) => console.log(v));
JavaScript 的数组就是 Object,这就意味着我们可以给数组添加字符串属性:
const arr = ["a", "b", "c"]; typeof arr; // 'object' arr.test = "bad"; // 添加非数字属性 arr.test; // 'abc' arr[1] === arr["1"]; // true, JavaScript数组只是特殊的Object
4 种循环语法,只有for/in
不会忽略非数字属性:
const arr = ["a", "b", "c"]; arr.test = "bad"; for (let i in arr) { console.log(arr[i]); // 打印"a, b, c, bad" }
正因为如此,使用for/in
遍历数组并不好。
其他 3 种循环语法,都会忽略非数字属性:
const arr = ["a", "b", "c"]; arr.test = "abc"; // 打印 "a, b, c" for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); } // 打印 "a, b, c" arr.forEach((el, i) => console.log(i, el)); // 打印 "a, b, c" for (const el of arr) { console.log(el); }
要点: 避免使用for/in
来遍历数组,除非你真的要想要遍历非数字属性。可以使用 ESLint 的guard-for-in规则来禁止使用for/in
。
JavaScript 数组可以有空元素。以下代码语法是正确的,且数组长度为 3:
const arr = ["a", , "c"]; arr.length; // 3
让人更加不解的一点是,循环语句处理['a',, 'c']
与['a', undefined, 'c']
的方式并不相同。
对于['a',, 'c']
,for/in
与forEach
会跳过空元素,而for
与for/of
则不会跳过。
// 打印"a, undefined, c" for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); } // 打印"a, c" arr.forEach(v => console.log(v)); // 打印"a, c" for (let i in arr) { console.log(arr[i]); } // 打印"a, undefined, c" for (const v of arr) { console.log(v); }
对于['a', undefined, 'c']
,4 种循环语法一致,打印的都是"a, undefined, c"。
还有一种添加空元素的方式:
// 等价于`['a', 'b', 'c',, 'e']` const arr = ["a", "b", "c"]; arr[5] = "e";
还有一点,JSON 也不支持空元素:
JSON.parse('{"arr":["a","b","c"]}'); // { arr: [ 'a', 'b', 'c' ] } JSON.parse('{"arr":["a",null,"c"]}'); // { arr: [ 'a', null, 'c' ] } JSON.parse('{"arr":["a",,"c"]}'); // SyntaxError: Unexpected token , in JSON at position 12
要点: for/in
与forEach
会跳过空元素,数组中的空元素被称为"holes"。如果你想避免这个问题,可以考虑禁用forEach
:
parserOptions: ecmaVersion: 2018 rules: no-restricted-syntax: - error - selector: CallExpression[callee.property.name="forEach"] message: Do not use `forEach()`, use `for/of` instead
for
,for/in
与for/of
会保留外部作用域的this
。
对于forEach
, 除非使用箭头函数,它的回调函数的 this 将会变化。
使用 Node v11.8.0 测试下面的代码,结果如下:
"use strict"; const arr = ["a"]; arr.forEach(function() { console.log(this); // 打印undefined }); arr.forEach(() => { console.log(this); // 打印{} });
要点: 使用 ESLint 的no-arrow-callback
规则要求所有回调函数必须使用箭头函数。
还有一点,forEach()
不能与 Async/Await 及 Generators 很好的"合作"。
不能在forEach
回调函数中使用 await:
async function run() { const arr = ['a', 'b', 'c']; arr.forEach(el => { // SyntaxError await new Promise(resolve => setTimeout(resolve, 1000)); console.log(el); }); }
不能在forEach
回调函数中使用 yield:
function run() { const arr = ['a', 'b', 'c']; arr.forEach(el => { // SyntaxError yield new Promise(resolve => setTimeout(resolve, 1000)); console.log(el); }); }
对于for/of
来说,则没有这个问题:
async function asyncFn() { const arr = ["a", "b", "c"]; for (const el of arr) { await new Promise(resolve => setTimeout(resolve, 1000)); console.log(el); } } function* generatorFn() { const arr = ["a", "b", "c"]; for (const el of arr) { yield new Promise(resolve => setTimeout(resolve, 1000)); console.log(el); } }
当然,你如果将forEach()
的回调函数定义为 async 函数就不会报错了,但是,如果你想让forEach
按照顺序执行,则会比较头疼。
下面的代码会按照从大到小打印 0-9:
async function print(n) { // 打印0之前等待1秒,打印1之前等待0.9秒 await new Promise(resolve => setTimeout(() => resolve(), 1000 - n * 100)); console.log(n); } async function test() { [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(print); } test();
要点: 尽量不要在forEach
中使用 aysnc/await 以及 generators。
简单地说,for/of
是遍历数组最可靠的方式,它比for
循环简洁,并且没有for/in
和forEach()
那么多奇怪的特例。for/of
的缺点是我们取索引值不方便,而且不能这样链式调用forEach()
. forEach()
for (let i in arr)
li >
for (const v of arr)
for
und for/in können wir auf den Index des Arrays statt auf den tatsächlichen Array-Elementwert zugreifen: 🎜for (const [i, v] of arr.entries()) { console.log(i, v); }🎜Mit
for/of
können wir direkt auf den Elementwert des zugreifen Array: 🎜 rrreee🎜Verwenden Sie forEach()
, Sie können gleichzeitig auf den Index- und Elementwert des Arrays zugreifen: 🎜rrreeefor/in
ignoriert nicht numerische Attribute nicht: 🎜rrreee🎜 Aus diesem Grund ist Usefor/in Das Iterieren über Arrays ist nicht gut🎜. 🎜🎜Die anderen 3 Schleifensyntaxen ignorieren nicht-numerische Attribute: 🎜rrreee🎜Punkte: Vermeiden Sie die Verwendung von for/in
zum Durchlaufen eines Arrays, es sei denn, Sie möchten wirklich Non iterieren -numerische Attribute. Sie können die guard-for-in🎜-Regeln von ESLint verwenden, um die Verwendung von zu deaktivieren für/in
. 🎜['a',, 'c']
und verarbeitet [ 'a', undefiniert, 'c']
sind nicht dasselbe. 🎜🎜Für ['a', 'c']
überspringen for/in
und forEach
leere Elemente, während for
und for/of
werden nicht übersprungen. 🎜rrreee🎜Für ['a', undefiniert, 'c']
sind die vier Schleifensyntaxen gleich und es wird „a, undefiniert, c“ gedruckt. 🎜🎜Es gibt eine andere Möglichkeit, leere Elemente hinzuzufügen: 🎜rrreee🎜Noch eine Sache: JSON unterstützt auch keine leeren Elemente: 🎜rrreee🎜Punkte: for/in
und forEach überspringt leere Elemente im Array ="nofollow">"Löcher"🎜. Wenn Sie dieses Problem vermeiden möchten, sollten Sie forEach
:🎜rrreeefor
,for/in und for/of
behalten this
im äußeren Bereich. 🎜🎜Für forEach
ändert sich die Funktion der Rückruffunktion, sofern keine Pfeilfunktionen verwendet werden. 🎜🎜Testen Sie den folgenden Code mit Node v11.8.0 und die Ergebnisse sind wie folgt: 🎜rrreee🎜Punkte: Verwenden Sie ESLints no-arrow-callback
🎜Die Regel erfordert, dass alle Rückruffunktionen Pfeilfunktionen verwenden müssen. 🎜forEach()
kann nicht gut mit Async/Await und Generatoren „kooperieren“. 🎜🎜Await kann nicht in der Rückruffunktion forEach
verwendet werden: 🎜rrreee🎜Yield kann nicht in der Rückruffunktion forEach
verwendet werden: 🎜rrreee🎜Für for/of
, es gibt kein solches Problem:🎜rrreee🎜Wenn Sie die Rückruffunktion von forEach()
als asynchrone Funktion definieren, erhalten Sie jedoch keine Fehlermeldung forEach
In der Reihenfolge ausführen 🎜 , es wird Kopfschmerzen vergleichen. 🎜🎜Der folgende Code gibt 0-9 von groß nach klein aus: 🎜rrreee🎜Punkte: Versuchen Sie, aysnc/await und Generatoren in forEach
nicht zu verwenden. 🎜for/of
der zuverlässigste Weg, ein Array zu durchlaufen. Es ist prägnanter als forcode>-Schleife. Und es gibt nicht so viele seltsame Sonderfälle wie <code>for/in
und forEach()
. Der Nachteil von for/of
besteht darin, dass es für uns unpraktisch ist, den Indexwert zu erhalten, und wir können forEach()
nicht aufrufen > in einer solchen Kette. 🎜使用for/of
获取数组索引,可以这样写:
for (const [i, v] of arr.entries()) { console.log(i, v); }
本文采用意译,版权归原作者所有
原文:http://thecodebarbarian.com/for-vs-for-each-vs-for-in-vs-for-of-in-javascript.html
相关免费学习推荐:js视频教程
更多编程相关知识,请访问:编程入门!!
Das obige ist der detaillierte Inhalt vonDer Unterschied zwischen den vier Array-Traversal-Methoden in JS ( for , forEach() , for/in, for/of). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!