Heim  >  Artikel  >  Web-Frontend  >  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)

青灯夜游
青灯夜游nach vorne
2020-10-27 17:58:112479Durchsuche

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)

语法

使用forfor/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; // &#39;object&#39;

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

arr.test; // &#39;abc&#39;
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/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);
}

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

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

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

还有一点,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

要点: 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

函数的 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); // 打印{}
});

要点: 使用 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);
  });
}

不能在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);
  });
}

对于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/inforEach()那么多奇怪的特例。for/of的缺点是我们取索引值不方便,而且不能这样链式调用forEach(). forEach()for (let i in arr) li >

for (const v of arr)

Syntax

🎜Verwenden Sie 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: 🎜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 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. 🎜

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 forEach überspringt leere Elemente im Array ="nofollow">"Löcher"🎜. Wenn Sie dieses Problem vermeiden möchten, sollten Sie forEach:🎜rrreee

function-this

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

Fazit

🎜Einfach ausgedrückt ist 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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:fundebug.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen