ES6迭代器学习笔记

JavaScript原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。

——《ECMAScript 6 入门:Iterator和for…of循环》(阮一峰)


迭代器

迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。

Iterator的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费。

工作原理

调用iterator接口时,返回一个iterator对象,调用该iterator对象的next方法。
每次调用next方法时返回可遍历对象的当前成员。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。

  • 模拟一个迭代器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function iterateFunc(array) {
var nextIdx = 0;
return {
next() {
return nextIdx < array.length ?
{ value: array[nextIdx++], done: false } :
{ done: true };
}
};
}
var it = iterateFunc(['a','b', 'c']);
for (var x in it) {
console.log(x);
}

调用迭代器的场合

  • 解构赋值
  • 扩展运算符 内部调用

  • 覆盖原生迭代器

1
2
3
4
5
6
7
8
9
10
11
12
String.prototype[Symbol.iterator] = function(){
var index = 0;
return {
next:() => {
return index < this.length ?
{ value: this[this.length -1 - index++], done: false } :
{ done: true };
}
};
};
NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
  • 为对象编写自定义迭代器
    iterator本质上是线性操作,但是对象的遍历顺序是非线形的,所以ES6没有为对象内置原生的[Symbol.iterator]()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]: function () {
var self = this;
var keys = Object.keys(self);
var index = 0;
return {
next: function () {
return index < keys.length ?
{ value: self[keys[index++]], done: false } :
{ done: true }
}
}
}
}

上述实现方式其实比较繁琐,利用Object.keys(obj).forEach(key => obj[key])其实效率更高


参考