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:
and for/in
, we can access the subscript of the array instead of the actual array element value: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">for (let i = 0; i < arr.length; ++i) {
console.log(arr[i]);
}
for (let i in arr) {
console.log(arr[i]);
}</pre><div class="contentsignin">Copy after login</div></div>
Using
, we can directly access the element value of the array : <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">for (const v of arr) {
console.log(v);
}</pre><div class="contentsignin">Copy after login</div></div>
Using
, you can access the subscript and element value of the array at the same time: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">arr.forEach((v, i) => console.log(v));</pre><div class="contentsignin">Copy after login</div></div>
Non-numeric attributes
const arr = ["a", "b", "c"]; typeof arr; // 'object' arr.test = "bad"; // 添加非数字属性 arr.test; // 'abc' arr[1] === arr["1"]; // true, JavaScript数组只是特殊的Object
4 loop syntaxes, only
for/in will not ignore non-numeric attributes: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">const arr = ["a", "b", "c"];
arr.test = "bad";
for (let i in arr) {
console.log(arr[i]); // 打印"a, b, c, bad"
}</pre><div class="contentsignin">Copy after login</div></div>
Because of this,
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); }
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
. The following code syntax is correct, and the array length is 3: const arr = ["a", , "c"];
arr.length; // 3
and ['a', undefined, 'c']
is not the same. For
, for/in
and forEach
will skip empty elements, while for
and for/of
will not be skipped. <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">// 打印"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);
}</pre><div class="contentsignin">Copy after login</div></div>
For
, the four loop syntaxes are the same, and "a, undefined, c" is printed. There is another way to add empty elements:
// 等价于`['a', 'b', 'c',, 'e']` const arr = ["a", "b", "c"]; arr[5] = "e";
One more thing, JSON does not support empty elements either:
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 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:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">parserOptions:
ecmaVersion: 2018
rules:
no-restricted-syntax:
- error
- selector: CallExpression[callee.property.name="forEach"]
message: Do not use `forEach()`, use `for/of` instead</pre><div class="contentsignin">Copy after login</div></div>
function of this
, for/in
and for/of
will retain this
of the outer scope. For
, 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); // 打印{} });
Use ESLint's no-arrow-callbackThe rules require that all callback functions must use arrow functions.
Async/Await and Generators
cannot "cooperate" well with Async/Await and Generators. Cannot use await in the
callback function: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">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);
});
}</pre><div class="contentsignin">Copy after login</div></div>
Cannot use yield in the
callback function: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">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);
});
}</pre><div class="contentsignin">Copy after login</div></div>
For
, there is no such problem: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">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);
}
}</pre><div class="contentsignin">Copy after login</div></div>
Of course, if you define the callback function of
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();
Try not to use aysnc/await in forEach and generators. Conclusion
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!