一、概念
遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
- 作用:
1)为各种数据结构,提供一个统一的、简便的访问接口;
2)使得数据结构的成员能够按某种次序排列;
3) ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。 - 实质:
Iterator创建一个指针对象,指向当前数据结构的起始位置,不断调用指针对象的next方法直到数据结构结束位置,遍历事先给定的数据结构
var it = makeIterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
};
}
二、 Symbol.iterator属性:
一个数据结构只要具有Symbol.iterator
属性,就可以认为是“可遍历的
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}
};
原生具备 Iterator 接口的数据结构如下:
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。
三、遍历器对象的 return(),throw()
遍历器对象的next()
方法是必须部署的,return()
方法(必须返回一个对象)和throw()
方法是否部署是可选的。return()
方法的使用场合是,如果for...of
循环提前退出,就会调用return()
方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return()
方法
function readLinesSync(file) {
return {
[Symbol.iterator]() {
return {
next() {
return { done: false };
},
return() {
file.close();
return { done: true };
}
};
},
};
}
throw()
方法主要是配合 Generator 函数使用,一般的遍历器对象用不到这个方法。
四、for...of 循环
for...of
循环内部调用的是数据结构的Symbol.iterator
方法,for...in
循环,只能获得对象的键名,for...of
循环,允许遍历获得键值
const arr = ['red', 'green', 'blue'];
for(let v of arr) {
console.log(v); // red green blue
}
对于普通的对象,for...of
结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用,可以使用for...in
循环遍历键名
let es6 = {
edition: 6,
committee: "TC39",
standard: "ECMA-262"
};
for (let e in es6) {
console.log(e);
}
// edition
// committee
// standard
for (let e of es6) {
console.log(e);
}
// TypeError: es6[Symbol.iterator] is not a function