迭代器(Iterator)
有时也称为遍历器 - 迭代器对象
作用
- 为各种数据结构提供
统一的访问接口
- 使数据结构的成员按照
某种次序排列
- 统一的迭代方式for...of循环
1.可迭代(iterable)
iterable:拥有Symbol.iterator
属性的数据结构是可迭代的
Symbol.iterator:值为迭代器生成函数
原生可迭代的数据结构:
- Array
- Map
- Set
- String
- TypedArray
- arguments
-
NodeList
这些数据结构均可以使用for...of来遍历
//以数组为例,判断是否有Symbol.iterator属性
const arr = [1, 2, 3, 4]
Symbol.iterator in arr //true
//for...of遍历数组
for(const i of arr){
console.log(i) //1 2 3 4
}
2.迭代器生成函数(Symbole.iterator)
返回一个迭代器对象
const arr = [1,2,3,4]
console.log(arr[Symbol.iterator]())
迭代器中有一个next函数
next()会返回一个成员对象,有value和done两个属性,value表示当前成员
的值,done表示遍历是否终止
for...of每次的遍历都会调用next函数并取value
2.1next()方法
const arr = [1, 2, 3, 4]
let iter = arr[Symbol.iterator]() //返回一个遍历器对象
console.log(iter.next());//{value: 1, done: false}
console.log(iter.next());//{value: 2, done: false}
console.log(iter.next());//{value: 3, done: false}
console.log(iter.next());//{value: 4, done: false}
console.log(iter.next());//{value: undefined, done: true}
2.2实现一个迭代器生成函数
数组
//实现
function makeIterator(arr) {
var nextIndex = 0;
return {
next() {
return nextIndex < arr.length ?
{ value: arr[nextIndex++], done: false } :
{ value: undefined, done: true }
}
}
}
//测试
const arr = [1]
let iter = makeIterator(arr)
console.log(iter.next()) //{value: 1, done: false}
console.log(iter.next());//{value: undefined, done: true}
- 对于对象也可以去实现一个迭代器生成函数,思路大致一样
- 但是对象上有丰富的方法间接生成一个数组,Object.values(obj)、keys、entries,这样就间接拥有了Symbol.iterator接口,可以使用for...of循环遍历
- 对于对象这种非线性的数据结构,部署迭代器接口相当于将其转化为线性结构,不如直接使用Map
生成器(Generator)
- 从语法和结构上看,封装了多个内部状态 -
状态机
- 从返回结果看,返回了一个迭代器对象 -
迭代器生成函数
形式
- functon与函数名之间有一个星号
*
-
内部使用
yield
语句定义不同的内部状态
function* generator(){
yield 1;
yield 2;
return 3;
}
1.next方法
1.1调用
调用生成器函数不会运行内部代码,会返回一个迭代器对象,上面有next方法
function* generator() {
console.log("a");
yield 1;
console.log("b");
return 2
console.log("c");
yield 3
}
let iter = generator()
console.log(iter);
console.log(iter.next());// "a" {value:1,done:false}
console.log(iter.next());// "b" {value:2,done:true}
console.log(iter.next());// {value:undefined,done:true}
第一次调用next会开始运行函数,从起始到第一个yield结束,返回yield后的状态
再调用next时会从上一个yield语句后开始执行,直到遇到下一个yield
当执行到return时,返回的对象done属性为true,且后续代码不再执行,下一调用返回{value:undefined,done:true}
yield不会终止只会中断且返回的done始终是false
1.2参数
next方法中可以添加参数,作为上一个yield的值,yield本身没有值
function* generator(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z)
}
let iter = generator(5)
console.log(iter.next());//{value: 6, done: false}
console.log(iter.next(12));//{value: 8, done: false}
console.log(iter.next(13));//{value: 42, done: true}
第一次返回结果为 x + 1 => 5 + 1
第二次的返回结果y由第一个yield计算而来,其值为第二个next()中的参数 2*12/3 = 8
z的值由第二个yield的值,其值为第三个next()中的参数 5 + 24 + 13 = 42
function* generator() {
let val1 = yield 1
console.log(""val1);
let val2 = yield 2
console.log(val2);
}
let iter = generator()
iter.next("one")
iter.next("two") //第一个yield的值:two
iter.next("three")//第二个yield的值:three