一、迭代器
迭代器(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署iterator接口,就可以完成遍历操作。
1.什么迭代
- 从一个数据集合中按照一定顺序,不断取出数据的过程我们就叫做迭代
2.迭代和遍历有什么区别?
- 遍历必须知道数据集合的长度,而迭代不需要
- 迭代强调的是依次取出,不能够确定到底能取出来多少,也不确定能不能把数据取完
3.迭代器需要满足的条件
- 迭代器必须有得到下一个数据的能力
- 判断是否有后续数据的能力
1.具备迭代器接口的数据,可以用for..of 遍历的数据:
- Array
- argument
- Set
- Map
- String
- TypedArray
- nodeList
2.工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
- 接下来不断地调用next方法,指针一直往后移动,直到指向最后一个成员
- 每调用next方法返回一个包含value和done属性的对象
3.可迭代对象上有这一个属性
const arr = [1, 2, 3, 4, 5]
console.log(arr);
//创建一个指针对象,由Symbol.iterator创建
let iterator = arr[Symbol.iterator]()
console.log(iterator); //具有next方法
//第一次调用next方法,指针自动指向数据结构的第一个成员
console.log(iterator.next()); //{value:1,done:false};done表示是否迭代完成
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next()); //{value:undefined,done:true};完成
自己模拟一个迭代器
const arr = [1, 2, 3, 4, 5]
const iterator = {
i: 0,
next() {
let result = {
value: arr[this.i],
done: this.i >= arr.length
}
this.i++;
return result;
}
}
let data = iterator.next()
while (!data.done) {
console.log(data.value)
data = iterator.next()
}
console.log("迭代完成")
4.自定义遍历数据
obj对象不是一个可迭代对象,不能用for..of遍历,因为没有Symbol.iterator,给obj写一个Symbol.iterator;
// 自定义可迭代obj
const obj = {
a: 1,
b: 2,
[Symbol.iterator]() { //for of一定会走进这个函数
const keys = Object.keys(this) //[a,b]
let i = 0;
return {
next: () => {
let propName = keys[i] //属性名
let propValue = this[propName]; //属性值
let result = {
value: {
propName,
propValue
},
done: i >= keys.length
}
i++;
return result;
}
}
}
}
const iter = obj[Symbol.iterator]()
console.log(iter.next()); //{done: false,value: {propName: 'a', propValue: 1}
console.log(iter.next()); //{done: false,value: {propName: 'b', propValue: 2}
console.log(iter.next()); //{done: true,value: {propName: undefined, propValue:undefined}
//可以用for..of遍历了
for (const iterator of obj) {
console.log(iterator)
}
二、生成器
生成器其实就是一个特殊的函数,
1.生成器的声明
调用生成器会产生一个生成器对象,具有next方法,调用这个方法会让生成器开始或恢复执行
next返回值类似迭代器
function* fun() {
console.log(1)
console.log(2)
console.log(3)
}
const iterator = fun()
console.log(iterator) //一个迭代器对象,具有next方法
iterator.next() //1 //2 //3
2.yield;函数代码的分割
生成器在遇到yield前正常执行,遇到后停止执行,再次调用next才能回复执行
function* fun() {
console.log(1)
yield 'a';
console.log(2)
yield 'b';
console.log(3)
}
const iterator = fun()
console.log(iterator.next()) //执行第一段代码 打印1 next返回结果:{value: 'a', done: false}
console.log(iterator.next()) //执行第二段代码 打印2
console.log(iterator.next()) //3 next返回{value: undefined, done: true}
遍历fun()
function* fun() {
console.log(1)
yield 'a';
console.log(2)
yield 'b';
console.log(3)
}
for (let v of fun()) {
console.log(v); //执行代码打印1 //v=a //执行代码打印2 //v=b //3
}
3.生成器函数的参数传递
调用生成的next方法时,可以传递参数,传递的参数会交给yield表达式作为返回值,第一次调用next方法时,传递的参数没有任何意义;
function* fun(arg) {
console.log(arg); //aaa
var one = yield 1;
console.log(one) //bbb
var two = yield 2;
console.log(two) //ccc
}
let iterator = fun('aaa')
console.log(iterator.next()) //{value : 1 , done : false}
console.log(iterator.next('bbb')) //{value : 2 , done : false}
console.log(iterator.next('ccc')) //{value : undefined , done : true}
4.API
- return()提前结束整个生成器函数,迭代过程也提前结束
- throw()可以在生成器内部跑出一个错误,抛出到对应的行
function* fun() {
console.log(1)
yield "a";
console.log(2)
yield 'b';
console.log(3)
yield 'c';
console.log(4)
}
let a = fun()
console.log(a.next()) //{value: 'a', done: false}
console.log(a.return()) //结束 {value: undefined, done: true}
console.log(a.next()) //{value: undefined, done: true}
a.throw(new Error("aaaa"))
5.在生成器内部用别的生成器
function* fun1() {
yield 'a';
yield 'b';
}
function* fun2() {
yield* fun1()
yield '1';
yield '2';
yield '3';
}
const a = fun2()
console.log(a.next());//{value: 'a', done: false}
console.log(a.next());//{value: 'b', done: false}
console.log(a.next());//{value: '1', done: false}
console.log(a.next());//{value: '2', done: false}