迭代器和生成器

75 阅读1分钟

迭代器

迭代器是一个具体的对象,他需要符合 迭代器协议

迭代器协议:对象中要求有一个 next 函数,这个next() ,只能没有参数或者有一个参数 ,而且需要返回一个 带有 { done:false/ true,value: xxx }的对象

如果迭代器可以产生下一个值的话,那么 done:false

如果迭代完成的话,done 会变为 true

const arr1 = [10,15,58,52]
let i = 0
const iterator = {
    next:function(){
        if( i < arr1.length ){
            return { done : false , value : arr1[i++] }
        }else {
            return {done : true , value : undefined}
        }
    }
}
console.log(iterator.next()) 
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

可迭代对象

当一个对象实现可迭代协议的时候,它就是可迭代对象

在代码中我们使用 Object.iterator 访问该属性

const obj = {
  arr1: [10, 15, 89, 25],
  [Symbol.iterator]: function () {
    let index = 0;
    // console.log(index,'-----');
    return {
      next: () => {
        if (index < this.arr1.length) {
          //为了能够访问到 arr1,要将arr1 改为 this.arr1 ,函数改为箭头函数
          return { done: false, value: this.arr1[index++] };
        } else {
          return { done: true, value: undefined };
        }
      },
    };
  },
};
​
const iterator1 = obj[Symbol.iterator](); //得到的是一个对象
console.log(iterator1.next());
console.log(iterator1.next());
console.log(iterator1.next());
console.log(iterator1.next());
console.log(iterator1.next());
​

迭代器对象的作用:使用for of 遍历对象的时候,就是取迭代器对象里面的值 .value

不停的调用 next(),然后取到 里面的 value

内置创建可迭代对象

String、array 、Set 、Map 、arguments对象等

里面内部都是自带可迭代对象的

可迭代对象的应用

for of 语法 、 展开运算符 、 解构运算符 、new Map( iterator )、new Set( iterator ) 、promise.all()

使用for of 语法的时候,是不断的的调用next(),然后获取里面的value值

展开运算符,也可以传递可迭代对象,取到里面Value的值,然后给新数组赋值

对象的展开运算是采用了别的方法,对里面的键值对进行遍历,然后给新的对象赋值

对象的解构赋值,也是采用了别的方式

迭代器在类中的使用

类方法正常来说是不能通过迭代器进行遍历的,但是可以给类加上 [Symbol.iterator] 方法

class classRoom{
    constructor(address,students){
        this.address = address
        this.students = students
    }
    entry(newStudents){
        this.students.push(newStudents)
    }
    [Symbol.iterator](){
        let index = 0
        return {
            next:()=>{
                if(index < this.students.length){
                    return { done :false, value:this.students[index++] }
                }else {
                    return { done :true , value :undefined}
                }
            }
        }
    }
}
​
​
const p1 = new classRoom('重庆',['aaa','bbb','ccc'])
​
for (const item of p1){
    console.log(item)
}

生成器函数

生成器函数需要在function 后面 + *

生成器函数可以通过yield 来控制函数的暂停和执行

生成器函数的返回值是一个 生成器

生成器是一种特殊的迭代器

function* Gen (){
    console.log('这是个生成器')
    let value1 = 100
    console.log('value1:',value1)
    const n = yield value1  //接收调用函数时传递进来的参数
    
    console.log('-------')
    value1 = 200 * n
    console.log('value2:',value1)
    yield
    
    console.log('-------')
    value1 = 300
    console.log('value3:',value1)
    yield    
    
    console.log('函数结束咯')
}
    Gen()  //直接执行函数没有任何输出
    const gen = Gen()
    console.log( gen.next() ) //执行第一个 yield往上的内容
    console.log( gen.next(2) ) //执行第二个 yield往上的内容
    console.log( gen.next() ) //执行第三个 yield往上的内容
    console.log( gen.next() ) //执行最后的全部内容
    value1: 100
结果:
​
这是个生成器
VM222:4 value1: 100
VM222:21 {value: 100, done: false}
VM222:7 -------
VM222:9 value2: 400
VM222:22 {value: undefined, done: false}
VM222:12 -------
VM222:14 value3: 300
VM222:23 {value: undefined, done: false}
VM222:17 函数结束咯
VM222:24 {value: undefined, done: true}
​
如果想要value里面有值的话,要通过 yield 后面加上值
​

传参

如果想要给后续的函数传递参数的话,要在第二个 gen.next() 里面加上参数,可以在上一个 yield里面接收到传递的参数

const n = yield

生成器的return方法

Gen.return() 当调用这个方法的时候,后续的方法调用 会返回 { done:true ,value:undefined } 的状态

console.log( gen.next() ) //执行第一个 yield往上的内容

Gen.return() 方法,上面的函数会正常执行,下面的函数不会正常执行,会返回

{ done:true ,value:undefined }

console.log( gen.next(2) ) //执行第二个 yield往上的内容 console.log( gen.next() ) //执行第三个 yield往上的内容 console.log( gen.next() )

生成器的throw方法

使用生成器的 throw 方法抛出异常,会给 yield 方法报错,可以使用 try ... catch 方法进行错误捕获

生成器代替迭代器

生成器代替迭代器,我们可以使用 yield 传入可迭代对象

//方法1
function* Gen (arr){
    for(const item of arr){
        yield item
    }
}
//我们调用 Gen函数通过往里面传入数组,遍历里面的元素,然后通过 yield就可以实现迭代器的功能
const names = ['aaa','bbb','ccc']
    const foo = Gen2(names)
    console.log(foo.next());
    console.log(foo.next());
    console.log(foo.next());
    console.log(foo.next());
​
结果:/*
{ value: 'aaa', done: false }
{ value: 'bbb', done: false }
{ value: 'ccc', done: false }
{ value: undefined, done: true }
*/
​
​
//方法2 function* Gen(arr){
    yield* arr
}
```结果同上```
我们通过调用yield* 的时候,要传入 可迭代对象,yield* 会自动迭代然后将数据传出
​
// 方法3 ,在类中使用生成器class Classroom {
    constructor(address,students){
        this.address = address
        this.studentd = students
    }
    [Symbol.iterator] = function* (){
        // for(const item of this.students){  
        //}
        yield* this.students
    }
}
​
const p1 = new Classroom('重庆',['aaa','bbb','ccc'])
//让类具有可迭代对象,就可以使用 for... of 进行遍历