ES6引入iterable类型以统一Array、Map和Set的遍历方式。本文详解for...of循环语法,对比其与for...in的历史遗留问题,并介绍Array、Set和Map中forEach方法的回调参数差异及适用场景。
ES6 iterable类型概述
传统方式遍历Array可使用下标索引,但Map和Set等集合类型不支持下标访问。为实现集合遍历的统一标准,ES6规范定义了iterable接口,Array、Map和Set均实现了该接口。
实现了iterable接口的集合对象,均可通过for ... of语法进行遍历操作。
for ... of是ES6新增的语法特性,建议先验证当前浏览器是否兼容:
'use strict';
var a = [1, 2, 3];
for (var x of a) {
}
alert('你的浏览器支持for ... of');
for...of循环遍历示例
使用for ... of遍历各类集合的具体示例如下:
var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array
alert(x);
}
for (var x of s) { // 遍历Set
alert(x);
}
for (var x of m) { // 遍历Map
alert(x[0] + '=' + x[1]);
}
for...of与for...in的区别
许多开发者会疑惑,与传统的循环有何本质区别?
for ... in循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。
若手动向Array实例添加自定义属性,循环会意外包含这些额外属性:
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
alert(x); // '0', '1', '2', 'name'
}
for ... in循环将把name包括在内,但Array的length属性却不包括在内。
for ... of循环则完全修复了这些问题,它只循环集合本身的元素:
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a) {
alert(x); // 'A', 'B', 'C'
}
上述现象正是引入for ... of循环的主要原因。
使用forEach方法遍历集合
更推荐的实践是直接调用iterable内置的方法,该方法接收回调函数并在每次迭代时自动执行。以Array为例:
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
alert(element);
});
需注意,是ES5.1标准引入的方法,使用前需确认浏览器支持情况。
Set集合的遍历方式与Array类似,但Set不包含索引信息,因此其回调函数的前两个参数均指向元素本身:
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
alert(element);
});
对于Map,其回调函数的参数顺序依次为value、key以及map实例本身:
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
alert(value);
});
若对部分参数不感兴趣,可利用JavaScript函数调用机制忽略多余参数。例如,仅需获取Array中的element时:
var a = ['A', 'B', 'C'];
a.forEach(function (element) {
alert(element);
});