美文网首页javascript
JavaScript 的 4 种数组遍历方法

JavaScript 的 4 种数组遍历方法

作者: 大毛哥的大哥 | 来源:发表于2019-03-26 13:13 被阅读0次

JavaScript 的 4 种数组遍历方法

for

for (let i = 0; i < arr.length; ++i)

forEach()

arr.forEach((v, i) => { /* ... */ })

for/in

for (let i in arr)

for/of

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遍历数组并不好。

要点: 避免使用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

函数的 this

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规则要求所有回调函数必须使用箭头函数。

Async/Await 与 Generators
还有一点,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/of获取数组索引,可以这样写:

for (const [i, v] of arr.entries()) {
console.log(i, v);
}

相关文章

  • JavaScript 的 4 种数组遍历方法

    JavaScript 的 4 种数组遍历方法 for forEach() for/in for/of 语法 使用f...

  • JavaScript中数组的方法: 1、数组中会对数组元素进行遍历的方法: 第一种:for (var inde...

  • JS 数组循环遍历方法的对比

    JS 数组循环遍历方法的对比 JavaScript 发展至今已经发展出多种数组的循环遍历的方法,不同的遍历方法运行...

  • 数组的foreach方法(遍历)

    数组的foreach方法(遍历) JavaScript forEach() 方法 ...

  • JavaScript语法和数据类型

    JavaScript有三种声明方法会 遍历数组的方法 数组的方法 1.concat() 将两个数组连接成一个新数组...

  • Js数组遍历方法对比总结

    引言: ES6为javascript为数组遍历提供了新的一种方式: for....of....。那之前的遍历方法各...

  • javascript循环性能比较

    1.数组循环遍历方法 javascript传统的数组遍历有for循环,while循环,以及for-in。本篇文章要...

  • Array数组循环全解1

    常用的11种数组遍历方法: 1、for循环语句2、forEach数组对象内置方法3、map数组对象内置方法4、fi...

  • js中forEach、for-in和for-of循环方法

    一、forEach循环遍历 常用遍历数组方法: 自JavaScript5之后可以使用内置的forEach方法: 写...

  • ES6之遍历语法

    如何使用遍历的 我们暂且以数组为例,javascript提供了多种遍历数组的方法,最开始我们可能习惯使用for循环...

网友评论

    本文标题:JavaScript 的 4 种数组遍历方法

    本文链接:https://www.haomeiwen.com/subject/xtsgvqtx.html