Heim > Web-Frontend > js-Tutorial > Der Unterschied zwischen den vier Array-Traversal-Methoden in JS ( for , forEach() , for/in, for/of)

Der Unterschied zwischen den vier Array-Traversal-Methoden in JS ( for , forEach() , for/in, for/of)

青灯夜游
Freigeben: 2020-10-28 17:46:22
nach vorne
2552 Leute haben es durchsucht

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 < arr.length; ++i)
  • < code>arr.forEach((v, i) => { /* ... */ })for (let i = 0; i < arr.length; ++i)
  • arr.forEach((v, i) => { /* ... */ })
  • for (let i in arr)
  • for (const v of arr)

语法

使用forfor/in,我们可以访问数组的下标,而不是实际的数组元素值:

for (let i = 0; i < arr.length; ++i) {
    console.log(arr[i]);
}

for (let i in arr) {
    console.log(arr[i]);
}
Nach dem Login kopieren

使用for/of,则可以直接访问数组的元素值:

for (const v of arr) {
    console.log(v);
}
Nach dem Login kopieren

使用forEach(),则可以同时访问数组的下标与元素值:

arr.forEach((v, i) => console.log(v));
Nach dem Login kopieren

非数字属性

JavaScript 的数组就是 Object,这就意味着我们可以给数组添加字符串属性:

const arr = ["a", "b", "c"];

typeof arr; // &#39;object&#39;

arr.test = "bad"; // 添加非数字属性

arr.test; // &#39;abc&#39;
arr[1] === arr["1"]; // true, JavaScript数组只是特殊的Object
Nach dem Login kopieren

4 种循环语法,只有for/in不会忽略非数字属性:

const arr = ["a", "b", "c"];
arr.test = "bad";

for (let i in arr) {
    console.log(arr[i]); // 打印"a, b, c, bad"
}
Nach dem Login kopieren

正因为如此,使用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);
}
Nach dem Login kopieren

要点: 避免使用for/in来遍历数组,除非你真的要想要遍历非数字属性。可以使用 ESLint 的guard-for-in规则来禁止使用for/in

数组的空元素

JavaScript 数组可以有空元素。以下代码语法是正确的,且数组长度为 3:

const arr = ["a", , "c"];

arr.length; // 3
Nach dem Login kopieren

让人更加不解的一点是,循环语句处理[&#39;a&#39;,, &#39;c&#39;][&#39;a&#39;, undefined, &#39;c&#39;]的方式并不相同。

对于[&#39;a&#39;,, &#39;c&#39;]for/inforEach会跳过空元素,而forfor/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);
}
Nach dem Login kopieren

对于[&#39;a&#39;, undefined, &#39;c&#39;],4 种循环语法一致,打印的都是"a, undefined, c"。

还有一种添加空元素的方式:

// 等价于`[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;,, &#39;e&#39;]`
const arr = ["a", "b", "c"];
arr[5] = "e";
Nach dem Login kopieren

还有一点,JSON 也不支持空元素:

JSON.parse(&#39;{"arr":["a","b","c"]}&#39;);
// { arr: [ &#39;a&#39;, &#39;b&#39;, &#39;c&#39; ] }

JSON.parse(&#39;{"arr":["a",null,"c"]}&#39;);
// { arr: [ &#39;a&#39;, null, &#39;c&#39; ] }

JSON.parse(&#39;{"arr":["a",,"c"]}&#39;);
// SyntaxError: Unexpected token , in JSON at position 12
Nach dem Login kopieren

要点: for/inforEach会跳过空元素,数组中的空元素被称为"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
Nach dem Login kopieren

函数的 this

forfor/infor/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); // 打印{}
});
Nach dem Login kopieren

要点: 使用 ESLint 的no-arrow-callback规则要求所有回调函数必须使用箭头函数。

Async/Await 与 Generators

还有一点,forEach()不能与 Async/Await 及 Generators 很好的"合作"。

不能在forEach回调函数中使用 await:

async function run() {
  const arr = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;];
  arr.forEach(el => {
    // SyntaxError
    await new Promise(resolve => setTimeout(resolve, 1000));
    console.log(el);
  });
}
Nach dem Login kopieren

不能在forEach回调函数中使用 yield:

function run() {
  const arr = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;];
  arr.forEach(el => {
    // SyntaxError
    yield new Promise(resolve => setTimeout(resolve, 1000));
    console.log(el);
  });
}
Nach dem Login kopieren

对于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);
    }
}
Nach dem Login kopieren

当然,你如果将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();
Nach dem Login kopieren

要点: 尽量不要在forEach中使用 aysnc/await 以及 generators。

结论

简单地说,for/of是遍历数组最可靠的方式,它比for循环简洁,并且没有for/inforEach()那么多奇怪的特例。for/of的缺点是我们取索引值不方便,而且不能这样链式调用forEach(). forEach()for (let i in arr)

for (const v of arr)

Syntax

🎜Verwenden Sie for und < Mit dem Code >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);
}
Nach dem Login kopieren
Nach dem Login kopieren
🎜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: 🎜rrreee

non-numeric attribute

🎜JavaScript-Array ist Objekt, was bedeutet, dass wir dem Array String-Attribute hinzufügen können: 🎜rrreee🎜 4 Schleifensyntaxen, nur for/in ignoriert nicht numerische Attribute nicht: 🎜rrreee🎜 Aus diesem Grund ist Use< code>for/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. 🎜

Leere Elemente eines Arrays

🎜JavaScript-Arrays können
Leeres Element 🎜. Die folgende Codesyntax ist korrekt und die Array-Länge beträgt 3: 🎜rrreee🎜 Was die Leute noch mehr verwirrt, ist, dass die Schleifenanweisung ['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 < Code >forEach überspringt leere Elemente im Array ="nofollow">"Löcher"🎜. Wenn Sie dieses Problem vermeiden möchten, sollten Sie forEach:🎜rrreee

function-this

🎜for,< code deaktivieren >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. 🎜

Async/Await und Generatoren

🎜Eine weitere Sache: 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</code >, es gibt kein solches Problem:🎜rrreee🎜Wenn Sie die Rückruffunktion von <code>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. 🎜

Fazit

🎜Einfach ausgedrückt ist for/of der zuverlässigste Weg, ein Array zu durchlaufen. Es ist prägnanter als for</. code>-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);
}
Nach dem Login kopieren
Nach dem Login kopieren

参考

本文采用意译,版权归原作者所有

原文: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!

Verwandte Etiketten:
Quelle:fundebug.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Aktuelle Ausgaben
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage