Home  >  Article  >  Web Front-end  >  The difference between the four array traversal methods in JS ( for , forEach() , for/in, for/of)

The difference between the four array traversal methods in JS ( for , forEach() , for/in, for/of)

青灯夜游
青灯夜游forward
2020-10-27 17:58:112491browse

The difference between the four array traversal methods in JS ( for , forEach() , for/in, for/of)

We have multiple ways to traverse JavaScript arrays or objects, and the differences between them are very confusing. Airbnb Coding StyleFor/in and for/of are prohibited, do you know why? This article will introduce in detail the differences between the following four loop syntaxes:

    for (let i = 0; i 2536d27c838c24ee72d1ca0e10a96143 { /* ... */ })
  • for (let i in arr )
  • for (const v of arr)
  • Syntax

Use

for

and for/in, we can access the subscript of the array instead of the actual array element value: <pre class="brush:js;toolbar:false;">for (let i = 0; i &lt; arr.length; ++i) { console.log(arr[i]); } for (let i in arr) { console.log(arr[i]); }</pre>Using

for/of

, we can directly access the element value of the array : <pre class="brush:js;toolbar:false;">for (const v of arr) { console.log(v); }</pre>Using

forEach()

, you can access the subscript and element value of the array at the same time: <pre class="brush:js;toolbar:false;">arr.forEach((v, i) =&gt; console.log(v));</pre>Non-numeric attributes

JavaScript array It is Object, which means that we can add string attributes to the array:

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 loop syntaxes, only

for/in

will not ignore non-numeric attributes: <pre class="brush:js;toolbar:false;">const arr = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]; arr.test = &quot;bad&quot;; for (let i in arr) { console.log(arr[i]); // 打印&quot;a, b, c, bad&quot; }</pre> Because of this,

it is not good to

use for/in to traverse an array. The other three loop syntaxes will ignore non-numeric attributes:

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);
}

Points:

Avoid using for/in to traverse the array unless you Really want to iterate over non-numeric properties. You can use ESLint's guard-for-in rule to disable the use of for/in. Empty elements of arrays

JavaScript arrays can have

empty elements

. The following code syntax is correct, and the array length is 3:

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

arr.length; // 3
What makes people even more confused is that the loop statement handles

['a',, 'c']

and ['a', undefined, 'c'] is not the same. For

['a',, 'c']

, for/in and forEach will skip empty elements, while for and for/of will not be skipped. <pre class="brush:js;toolbar:false;">// 打印&quot;a, undefined, c&quot; for (let i = 0; i &lt; arr.length; ++i) { console.log(arr[i]); } // 打印&quot;a, c&quot; arr.forEach(v =&gt; console.log(v)); // 打印&quot;a, c&quot; for (let i in arr) { console.log(arr[i]); } // 打印&quot;a, undefined, c&quot; for (const v of arr) { console.log(v); }</pre>For

['a', undefined, 'c']

, the four loop syntaxes are the same, and "a, undefined, c" ​​is printed. There is another way to add empty elements:

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

One more thing, JSON does not support empty elements either:

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

Points:

for/in and forEach will skip empty elements. Empty elements in the array are called "holes". If you want to avoid this problem, consider disabling the forEach:<pre class="brush:js;toolbar:false;">parserOptions: ecmaVersion: 2018 rules: no-restricted-syntax: - error - selector: CallExpression[callee.property.name=&quot;forEach&quot;] message: Do not use `forEach()`, use `for/of` instead</pre> function of this

for

, for/in and for/of will retain this of the outer scope. For

forEach

, unless an arrow function is used, the this of its callback function will change. Use Node v11.8.0 to test the following code, the results are as follows:

"use strict";

const arr = ["a"];

arr.forEach(function() {
    console.log(this); // 打印undefined
});

arr.forEach(() => {
    console.log(this); // 打印{}
});

Points:

Use ESLint's no-arrow-callbackThe rules require that all callback functions must use arrow functions. Async/Await and Generators

One more thing,

forEach()

cannot "cooperate" well with Async/Await and Generators. Cannot use await in the

forEach

callback function: <pre class="brush:js;toolbar:false;">async function run() { const arr = [&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;, &amp;#39;c&amp;#39;]; arr.forEach(el =&gt; { // SyntaxError await new Promise(resolve =&gt; setTimeout(resolve, 1000)); console.log(el); }); }</pre>Cannot use yield in the

forEach

callback function: <pre class="brush:js;toolbar:false;">function run() { const arr = [&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;, &amp;#39;c&amp;#39;]; arr.forEach(el =&gt; { // SyntaxError yield new Promise(resolve =&gt; setTimeout(resolve, 1000)); console.log(el); }); }</pre> For

for/of

, there is no such problem: <pre class="brush:js;toolbar:false;">async function asyncFn() { const arr = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]; for (const el of arr) { await new Promise(resolve =&gt; setTimeout(resolve, 1000)); console.log(el); } } function* generatorFn() { const arr = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]; for (const el of arr) { yield new Promise(resolve =&gt; setTimeout(resolve, 1000)); console.log(el); } }</pre> Of course, if you define the callback function of

forEach()

as an async function, no error will be reported However, if you want forEach to be executed in order, it will be a headache. The following code will print 0-9 from large to small:

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();

Points:

Try not to use aysnc/await in forEach and generators. Conclusion

Simply put,

for/of

is the most reliable way to traverse an array. It is more concise than the for loop and has no for/in and forEach()So many strange special cases. The disadvantage of for/of is that it is inconvenient for us to get the index value, and we cannot call forEach(). forEach() in a chain like this. <p>使用<code>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视频教程

更多编程相关知识,请访问:编程入门!!

The above is the detailed content of The difference between the four array traversal methods in JS ( for , forEach() , for/in, for/of). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:fundebug.com. If there is any infringement, please contact admin@php.cn delete