我们有多种方法来遍历 javascript 的数组或者对象,而它们之间的区别非常让人疑惑。airbnb 编码风格禁止使用 for/in 与 for/of,你知道为什么吗?
这篇文章将详细介绍以下 4 种循环语法的区别:
for (let i = 0; i 94ffee46481db95b32f32d90a564f64d { /* ... */ })for (let i in arr)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遍历数组并不好。
其他 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/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: 2018rules: no-restricted-syntax: - error - selector: callexpression[callee.property.name="foreach"] message: do not use `foreach()`, use `for/of` instead
函数的 thisfor,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);}
参考for-each over an array in javascript?
why is using “for…in” with array iteration a bad idea?array iteration and holes in javascrip
本文采用意译,版权归原作者所有
原文:http://thecodebarbarian.com/for-vs-for-each-vs-for-in-vs-for-of-in-javascript.html
相关免费学习推荐:js视频教程
更多编程相关知识,请访问:编程入门!!
以上就是js中4种数组遍历方法( for 、foreach() 、for/in、for/of)的区别的详细内容。