ES6-20【iterator与generator】

一.Iterator

(1).实现原理

重点就是先获取后++

function makeIterator(arr){
        var iterRatorIndex = 0;
        return{
            next(){
              return  arr.length > iterRatorIndex ? 
               {value:arr[iterRatorIndex++],done:false}:
               {value:undefined,done:true}

            }
        }
    }
    var test = makeIterator(['a','b']);
    console.log(test.next());//{value: "a", done: false}

迭代器模式:结构化,从源以一次一个的方式抽取

迭代器:是一种有序的,连续的,继续抽取的组织方式

(2).内外部迭代器

内部迭代器 系统写好的

外部迭代器 外面自己写的

(3).迭代器迭代对象

普通方式处理

对象不具备迭代器接口,因为对象是无序的所以不能抽取

自己实现

let obj = {
        start:[1,3,2],
        end:[7,8,9],
        [Symbol.iterator](){
            let arr = [...this.start,...this.end];
            let iterRatorIndex = 0;
            return{
            next(){
              return  arr.length > iterRatorIndex ? 
               {value:arr[iterRatorIndex++],done:false}:
               {value:undefined,done:true}

            }
        }
        }
    }
  for(let a of obj){
      console.log(a);
      
  }// 1 3 2 7 8 9

map方式处理

map结构则是有序的,让对象和map一样

可迭代的数据类型

  1. array
  2. map
  3. set
  4. string
  5. typeArray
  6. NodeList
  7. arguments

let obj = {
        a:1,
        b:2,
        [Symbol.iterator]() {
            let map = new Map();
            for (let [key, value] of Object.entries(obj)) {
              map.set(key, value);
            }
            let mapArr = [...map.entries()];
            
            let iterRatorIndex = 0;
            return {
                next() {
                    return mapArr.length > iterRatorIndex ?
                        { value: mapArr[iterRatorIndex++],done:false}:
               {value:undefined,done:true}

            }
            }
        }
    }
  for(let a of obj){
      console.log(a);
      
  }
  //(2) ["a", 1]
        ["b", 2]
  抽取
  var a = obj[Symbol.iterator]();
    console.log(a.next());
      {value: Array(2), done: false}  

用for(let [key,value] of Object.entries(obj))也能解决这个问题,但是不能实现抽取

默认会调用iterator的情况

  1. ...拓展运算符
  2. for of
  3. Array.from()
  4. map set
  5. Promise.all()/race() yield

(4).return

终止for循环的方法都会触发return方法

let obj = {
        a:1,
        b:2,
        [Symbol.iterator]() {
            let map = new Map();
            for (let [key, value] of Object.entries(obj)) {
              map.set(key, value);
            }
            let mapArr = [...map.entries()];
            
            
            let iterRatorIndex = 0;
            return {
                next() {
                    return mapArr.length > iterRatorIndex ?
                        { value: mapArr[iterRatorIndex++],done:false}:
               {value:undefined,done:true}

            },
            return() {
                console.log('触发了错误');
               
            }
            }
        }
    }
for(var c of obj){
    console.log(c);
    throw new Error('错误')
   
    
}
["a", 1]
 触发了错误
Uncaught Error: 错误

二.generator

生成器函数,返回的都是迭代器对象

(1).基本形式

function * test(){}
let iter = test();
console.log(iter);


 

(2).yield

产出的意思,返回的均为迭代器对象

function * test(){
    console.log(1);   
    yield 'a';
    console.log(2);
    yield 'b';
    console.log(3); 
    let a = yield '5'
    console.log(a);
    return 'd';
    yield 'c';
   
}
let iter = test();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());

1
{value: "a", done: false}
2
{value: "b", done: false}
3
undefined
{value: "d", done: true}
{value: undefined, done: true}
{value: undefined, done: true}
  1. 与抽取的方式相同,会有产出值(迭代器对象)
  2. yield相当于一个区块,每一个区块的代码内容则为yield上方的代码,如果不next则不执行区块代码
  3. return后 之后所有的yield的产出值均为undefined
  4. 生成函数和yield和异步函数结合,就可以理解为状态机
  5. 也可以理解为生成迭代器函数
  6. yield本身是不返回值的,只能在外部通过next抽取函数获取,内部是un

yield/return区别

yield 暂停 有记忆的功能

return 结束 没有记忆功能

yield只能出现在生成器函数中 否则会报错

嵌套使用yield

yield是一个单独的表达式,嵌套使用要加()

function * test(){
    console.log('hello'+(yield 123)); 
   
}
let iter = test();
console.log(iter.next());
{value: 123, done: false}

yield作为参数传递

function * test(){
    foo(yield 'a',yield 'c')
   
}
function foo(a,b){
    console.log(a,b);
    
}
let iter = test();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
{value: "a", done: false}
{value: "c", done: false}
 undefined undefined
{value: undefined, done: true}

作为参数传递时 也会先yield返回产出一次

function * test(){
    yield 1;
    yield 2;
    yield 3;
    yield 4;
    yield 5;
   
}
for(let i of test()){
    console.log(i);
    
}
//1 2 3 4 5

通过next给yield传参

永远拿不到第一次的值,所以第一个参数没必要传

function * test(){
    
    let value1 = yield 1;
    console.log('value1'+value1);  
    let value2 = yield 2;
    console.log('value2'+value2);  
    let value3 = yield 3;
    console.log('value3'+value3);  
    let value4 = yield 4;
    console.log('value4'+value4);
}

let iter = test();
console.log(iter.next('none'));
console.log(iter.next('two'));
console.log(iter.next('three'));
{value: 1, done: false}
value1two
{value: 2, done: false}
value2three
{value: 3, done: false}

yield作为函数迭代使用

因为yield得产出值就为迭代函数,所以可以直接用yield去替代以前next的写法

l

let obj = {
    start:[1,2,3],
    end:[4,5,6],
    [Symbol.iterator] : function*(){
        var itemIndx = [...this.start,...this.end],
            length = itemIndx.length,
            idxof = 0;
            
         while(length>idxof){
             yield itemIndx[idxof++]
         }   
        
    }
}
for(var c of obj){
    console.log(c);
    
}
console.log(obj[Symbol.iterator]().next());
// 1 2 3 4 5 6 {value: 1, done: false}

(3).generator状态机

let fs = require('fs')
function promisify(fn){
    return function(...args){
        return new Promise((resolve,reject)=>{
            fn(...args,(err,data)=>{
                if(data){
                    resolve(data)
                }else{
                    reject(err)
                }
            })
        })
    }
}    
let readFile = promisify(fs.readFile)
function * read(){
    let value1 = yield readFile('./name.txt','utf-8');
    let value2 = yield readFile(value1,'utf-8');
    let value3 = yield readFile(value2,'utf-8');
    console.log(value3);
    
}
let iter = read();
let {value,done} = iter.next();
value.then((val)=>{
   let{value,done} = iter.next(val)
    value.then((val2)=>{
        let{value,done} = iter.next(val2)
        value.then((value)=>{
            console.log(value);
        })
    })
    
})
输出最后一个文件中的值99
  1. 首先通过Promisify把异步函数promise化
  2. 再通过生成函数 调用每一个异步函数 这样就可以通过next()调取下一个异步函数,并将上一个的异步函数结果通过next函数传参了,且返回Promise对象这样就可以通过then监听到了

函数提纯

因为每次获得结果都要通过上面的嵌套next()获得,特别麻烦,所以生成了CO

Co是TJ写的

function  Co(iter){
    return new Promise((resolve,reject)=>{
        let next = (data) =>{
            let {value,done} = iter.next(data);
            if(done){
                resolve(value)
            }else{
                value.then((val)=>{
                    next(val);
                })
            }
        }
        next();
    })
}
let promise = Co(read())
promise.then((val)=>{
    console.log(val);
    
})
结果与上方next then嵌套结果一致

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值