js 中几种遍历数组的方法比较

571 阅读3分钟

遍历如下的数组

let arr = [0, 1, 2, 3];
arr.length = 5;
delete arr[3];
arr.name = 'name';
arr.__proto__.id = 'id';
// arr => [0, 1, 2, empty, empty]

for

最传统的循环方法,也是速度最快的方法。

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

for (let i = 0; i < arr.length; i++) {
  if (i > 0) {
    // break;
    return false; // break 和 return false 可以中断循环
  }
  console.log(arr[i]); // 0
}

forEach

forEach 对数组中的每一个元素都执行一次回调函数。可以看做阉割版的 map

稀疏数组未被初始化的项或者被 delete 删除的项会被跳过。

forEach 不可以中断,但可以提前 return 跳过。

arr.forEach((item) => {
  console.log(item); // 0 1 2
});

arr.forEach((item, index) => {
  console.log('start');
  if (index > 0) {
    return;
  }
  console.log(item); // start 0 start start
});

map

map 对数组中的每一个元素都执行一次回调函数,并用回调函数的返回值组成一个新数组返回,默认返回 undefined

稀疏数组未被初始化的项或者被 delete 删除的项会被跳过。

arr.map((item) => {
  console.log(item); // 0 1 2
})

for in

for in 会对对象所有可枚举 (enumerable)的属性都会变量,包括原型链上面的属性。

稀疏数组未被初始化的项或者被 delete 删除的项会被跳过。

for (let i in arr) {
  console.log(arr[i]); // 0 1 2 name id
}

for (let i in arr) {
  if (i > 0) {
    break;
  }
  console.log(arr[i]); // 0
}

let obj = {
  name: 'name',
  number: 18
};
obj.__proto__.id = 'id2';
for (let i in obj) {
  console.log(obj[i]); // name 18 id2
}

for of

for-of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。只要是一个可迭代(iterable)的对象,就可以通过for-of来迭代.

for (let value of arr) {
  console.log(value); // 0 1 2 undefined undefined
}

for (let value of arr) {
  if (value === 1) {
    break;
  }
  console.log(value); // 0
}

for await ... of

function alarm(item) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(item);
      resolve();
    }, 2000);
  });
}

for await (let value of arr) {
  await alarm(value); // 0 1 2 undefined undefined,间隔两秒依次 log
}

function alarm(item) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(item);
      resolve();
    }, 2000);
  });
}

for await (let value of arr) {
  if (value === 1) {
    break;
  }
  await alarm(value); // 0
}

测试速度

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

console.time('for');
for (let i = 0; i < length; i++) {}
console.timeEnd('for');

console.time('forEach');
arr.forEach(() => {});
console.timeEnd('forEach');

console.time('map');
arr.map(() => {});
console.timeEnd('map');

console.time('forIn');
for (let i in arr) {
}
console.timeEnd('forIn');

console.time('forOf');
for (let value of arr) {
}
console.timeEnd('forOf');

在 2017 13" i5 MacBook Pro 的 Chrome 浏览器 79.0.3945.117 版本中,测试速度结果如下:

for: 3ms 左右 forEach: 12 ms 左右 map: 20 ms 左右 for in: 160 ~ 200 ms 左右 for of: 40 ms 左右

for forEach map for in for of for await ... of
可遍历类型 本质是一个计数器,不负责遍历 数组 数组 对象的可枚举属性 可迭代对象
能否遍历空值
能否 break
能否 continue
能否获取索引
速度 1 2 3 5 4
特点 遍历对象及其原型链上的所有可枚举属性