JavaScript中数组循环(for each)的方法 JavaScript 提供了多种强大的语义来遍历数组和类数组对象。本文将分别介绍针对真实数组和类数组对象的循环方法。
技术背景 在 JavaScript 编程中,经常需要对数组进行遍历操作,以处理数组中的每个元素。不同的循环方法适用于不同的场景,例如同步或异步操作、稀疏数组处理等。了解这些方法的特点和使用场景,有助于编写更高效、更清晰的代码。
实现步骤 针对真实数组 使用 for-of
(隐式使用迭代器,ES2015+) :ES2015 为 JavaScript 添加了迭代器和可迭代对象的概念,数组是可迭代对象。for-of
语句可以遍历迭代器返回的值。1 2 3 4 const a = ["a" , "b" , "c" ];for (const element of a) { console .log (element); }
使用 forEach
及相关方法(ES5+) :在支持 ES5 的环境中,可以使用 forEach
方法处理同步代码。该方法接受一个回调函数,会为数组中的每个元素依次调用该回调函数。1 2 3 4 const a = ["a" , "b" , "c" ]; a.forEach ((element ) => { console .log (element); });
ES5 还定义了其他一些有用的数组方法,如 every
、some
、filter
、map
、reduce
和 reduceRight
。
使用简单的 for
循环 :这是一种传统的循环方式,通过控制索引来遍历数组。1 2 3 4 5 const a = ["a" , "b" , "c" ];for (let index = 0 ; index < a.length ; ++index) { const element = a[index]; console .log (element); }
在性能敏感的代码中,可以提前获取数组长度,以提高性能。
1 2 3 4 5 const a = ["a" , "b" , "c" ];for (let index = 0 , len = a.length ; index < len; ++index) { const element = a[index]; console .log (element); }
也可以反向遍历数组。
1 2 3 4 5 const a = ["a" , "b" , "c" ];for (let index = a.length - 1 ; index >= 0 ; --index) { const element = a[index]; console .log (element); }
正确使用 for-in
:for-in
主要用于遍历对象的属性,而不是数组。但在处理稀疏数组或需要遍历数组对象的非元素属性时,可以使用 for-in
,但需要添加适当的检查。1 2 3 4 5 6 7 8 9 10 const a = []; a[0 ] = "a" ; a[10 ] = "b" ; a[10000 ] = "c" ;for (const name in a) { if (Object .hasOwn (a, name) && /^0$|^[1-9]\d*$/ .test (name) && name <= 4294967294 ) { const element = a[name]; console .log (a[name]); } }
显式使用迭代器(ES2015+) :for-of
隐式使用迭代器,也可以显式使用迭代器来遍历数组。1 2 3 4 5 6 7 const a = ["a" , "b" , "c" ];const it = a.values ();let entry;while (!(entry = it.next ()).done ) { const element = entry.value ; console .log (element); }
针对类数组对象 类数组对象具有 length
属性和以数字命名的属性,如 NodeList
、HTMLCollection
和 arguments
对象等。
使用上述大部分方法 :使用 for-of
(ES2015+) :许多类数组对象支持迭代,可以使用 for-of
进行遍历。1 2 3 4 const divs = document .querySelectorAll ("div" );for (const div of divs) { div.textContent = Math .random (); }
- **使用 `forEach` 及相关方法(ES5+)**:可以通过 `Function#call` 或 `Function#apply` 将 `Array.prototype` 上的方法应用于类数组对象。
1 2 3 Array .prototype .forEach .call (node.childNodes , (child ) => { });
- **使用简单的 `for` 循环**:简单的 `for` 循环同样适用于类数组对象。
- **显式使用迭代器(ES2015+)**:与数组类似,可以显式使用迭代器遍历类数组对象。
创建真实数组 :使用 Array.from
:Array.from
可以从类数组对象创建数组,还可以通过映射函数对元素进行转换。1 const divs = Array .from (document .querySelectorAll ("div" ));
- **使用扩展语法 (`...`)**:ES2015 的扩展语法可以使用对象的迭代器将类数组对象转换为真实数组。
1 const divs = [...document .querySelectorAll ("div" )];
- **使用数组的 `slice` 方法**:可以使用 `Array.prototype.slice.call` 将类数组对象转换为真实数组。
1 const divs = Array .prototype .slice .call (document .querySelectorAll ("div" ));
最佳实践 当处理异步操作时,优先使用 for-of
或简单的 for
循环,因为它们支持 async/await
。 对于同步操作,forEach
是一个简洁的选择,但要注意它不支持 async/await
。 处理稀疏数组时,可以考虑使用 for-in
并添加适当的检查。 当需要对数组元素进行转换或过滤时,使用 map
、filter
等方法。 常见问题 for-in
的问题 :for-in
会遍历对象的所有可枚举属性,包括继承的属性,并且遍历顺序不固定。因此,除非有特殊需求,否则不建议使用 for-in
遍历数组。forEach
与异步操作 :forEach
不支持 async/await
,如果在回调函数中使用异步操作,forEach
不会等待异步操作完成就会继续执行。可以使用 for-of
或简单的 for
循环代替。旧浏览器兼容性问题 :一些方法(如 for-of
、forEach
等)在旧浏览器中可能不支持,需要使用 polyfill 或采用其他兼容的方法。