Iterator 和 for...of
Iterator 的作用有三个:
- 是为各种数据结构,提供一个统一的、简便的访问接
- 是使得数据结构的成员能够按某种次序排列
- 是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费
部署方式
原生就具有iterator的数据结构
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
ES6 规定,默认
的 Iterator 接口部署在数据结构的Symbol.iterator
属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。Symbol.iterator属性本身是一个函数
,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器
。至于属性名Symbol.iterator,它是一个表达式
,返回Symbol对象的iterator属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内
// 为一个对象直接部署
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}
};
一个数据结构执行的for..of.. 循环,就会执行该数据结构的[Symbol.iterator]()
obj[Symbol.iterator]()
执行之后返回一个遍历器对象,其中next()
方法用来移动指针,定义每一次遍历的操作
throw()方法
return()方法的使用场合是,如果for...of循环提前退出(通常是因为出错,或者有break语句),就会调用return()方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return()方法。
function readLinesSync(file) {
return {
[Symbol.iterator]() {
return {
next() {
return { done: false };
},
return() {
file.close();
return { done: true };
}
};
},
};
}
//以下都会调用return方法
// 情况一
for (let line of readLinesSync(fileName)) {
console.log(line);
break;
}
// 情况二
for (let line of readLinesSync(fileName)) {
console.log(line);
throw new Error();
}
对象部署iterator的方式
使用类
class RangeIterator {
constructor(start, stop) {
this.value = start;
this.stop = stop;
}
[Symbol.iterator]() { return this; } // 使用for of 循环是默认调用此方法 返回当前的实例化对象,该对象有一个next方法
next() { // 返回值定义了该iterator的操作
var value = this.value;
if (value < this.stop) {
this.value++;
return {done: false, value: value};// done: false 可以省略
}
return {done: true, value: undefined };// value: undefined 可以省略
}
}
function range(start, stop) {
return new RangeIterator(start, stop);
}
for (var value of range(0, 3)) {
console.log(value); // 0, 1, 2
}
构造函数的原型链上部署
function Obj(value) {
this.value = value;
this.next = null;
}
Obj.prototype[Symbol.iterator] = function() {
var iterator = { next: next };
var current = this;
function next() {
if (current) {
var value = current.value;
current = current.next;
return { done: false, value: value };
} else {
return { done: true };
}
}
return iterator;
}
var one = new Obj(1);
var two = new Obj(2);
var three = new Obj(3);
one.next = two; // 修改指针指向 保证Iterator的功能
two.next = three;
for (var i of one){
console.log(i); // 1, 2, 3
}
类数组部署
类似数组的对象(存在数值键名和length属性),部署 Iterator 接口,有一个简便方法,就是Symbol.iterator方法直接引用数组的 Iterator 接口。
或者直接转换成为类数组
- 普通对象部署数组的Symbol.iterator方法,并无效果
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
// 或者
NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
[...document.querySelectorAll('div')] // 可以执行了