生成器和迭代器

文章推荐:https://juejin.cn/post/6844903717246861320#heading-0

迭代器

任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)

  • 为各种数据结构,提供一个统一的、简便的访问接口;

  • 使得数据结构的成员能够按某种次序排列

  • ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。

原生具备iterator接口的数据

  • Array
  • set容器
  • map容器
  • String
  • 函数的 arguments 对象
  • NodeList 对象

迭代器的工作原理

  • 创建一个指针对象,指向数据结构的起始位置。
  • 第一次调用next方法,指针自动指向数据结构的第一个成员
  • 接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
  • 每调用next方法返回的是一个包含value和done的对象,{value: 当前成员的值,done: 布尔值}
    • value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束。
    • 当遍历结束的时候返回的value值是undefined,done值为true
//手写一个迭代器
function Iterator(arr){
    let index = 0;
    return {
        next:function(){
            return index<arr.length?{value:arr[index++],done:false}:{value:undefined,done:true};
        }
    }
}
let arr = [1,4,'abc'];
let iterator = new Iterator(arr);
console.log(iterator.next()); // {val:1,done:false}
console.log(iterator.next()); // {val:4,done:false}
console.log(iterator.next()); // {val:'abc',done:false}
console.log(iterator.next()); // {val:undefined,done:true}
  • 注意:当使用for of去遍历某一个数据结构的时候,首先去找Symbol.iterator,找到了就去遍历,没有找到的话不能遍历,提示Uncaught TypeError: XXX is not iterable, 因此for of循环不支持遍历普通对象

生成器

推荐视频:https://www.bilibili.com/video/BV1Rp4y1v7AH?from=search&seid=10099126301110882575

概念

  • Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
  • 语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态
  • Generator 函数除了状态机,还是一个遍历器对象生成函数
  • 可暂停函数(惰性求值), yield可暂停,next方法可启动。每次返回的是yield后的表达式结果

特点

  • function关键字与函数名之间有一个星号
  • 函数体内部使用yield表达式,定义不同的内部状态

(大白话解释就是生成函数要加*,能用yield暂停函数执行,能用next继续启动,是不是很像迭代器。我们可以把yield看成播放器暂停,next看成继续播放)

 function* generatorExample(){
    console.log("开始执行")
    yield 'hello';  
    yield 'generator'; 
     return 'complete'
 }
// generatorExample() 
// 这种调用方法Generator 函数并不会执行
let MG = generatorExample() // 返回指针对象
MG.next() //开始执行  {value: "hello", done: false}
MG.next() //开始执行  {value: "generator", done: false}
MG.next() //开始执行  {value: "complete", done: true}
  • 作用域独立
function* xxfn(){
    var n = 1;
    yield ++n;
    yield ++n;
    yield ++n;
}

var aa = xxfn();
var bb = xxfn();

//aa,bb两个迭代器作用域独立
  • .next()方法可以接收参数

    • 传入参数,把上一个yield返回值给覆盖了
    • 第一个.next()方法其实是启动器,之前没有yield语句,因此传参无意义
    function* xxfn(){
        var n = 1;
        var v = yield n+22;
        console.log('aa---'+v);
        yield ++n;
        yield ++n;
    }
    var xxfn= xxfn();
    
    console.log(xxfn.next()); //23
    xxfn.next('abc'); // aa--- abc
    console.log(xxfn.next()); // 3

图片说明