Iterator的概念
遍历器的遍历过程:
- 创建一个指针对象,指向当前数据结构的起点。
- 不断调用指针对象next方法指向下一个成员
- 每次调用时会返回{value:xxx,done:bool}的对象
- 默认值为done:false,value:undefined
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};
}
};
}
将一个对象变成可遍历的:
const obj={
[Symbol.iterator]:function(){
return {
next:function(){
return {
value:1,
done:true
}
}
}
}
}
注意一个类数组对象可以这样使用:
let iterable = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable){
console.log(item);
}
//普通对象不行
let iterable={
a:'a',
b:'b',
c:'c',
}
调用Iterator接口的场合:
- 解构赋值:对数组和Set解构赋值时默认调用Symbol.iterator方法
- 扩展运算符...会调用默认的Iterator接口.[...str]
- yield*
//yield*后面跟着可遍历结构,也会调用遍历器接口。
let generator=function*(){
yield 1;
yield*[2,3,4];
yield 5;
};
var iterator=generator();
iterator.next();
字符串的Iterator接口:
通过覆盖原生Symbol.iterator方法可以修改遍历器行为,迭代器的实现需要结合Generator函数上.
除了配置迭代器方法还可以使用return方法,return在for...of循环提前退出时调用:
function readLinesSync(file) {
return {
[Symbol.iterator]() {
return {
next() {
return { done: false };
},
return() {
file.close();
return { done: true };
}
};
},
};
}
for...of循环可以循环数组,Set和Map结构类似数组对象(如argument对象,DOM的NodeList对象,以及后文中的Generator对象及字符串),均具有Symbol.iterator
(PS:for...in...只能获取对象的键名,不能获取键值)
//对于数组迭代器来说for...of只可以返回数字索引的属性
let arr = [3, 5, 7];
arr.foo = 'hello';
for (let i in arr) {
console.log(i); // "0", "1", "2", "foo"
}
for (let i of arr) {
console.log(i); // "3", "5", "7"
}
使用Array.from将类数组对象转为数组之后就可以使用迭代器了。
forEach的缺点就是不能使用break,continue,return等.