ES6学习笔记十二:迭代器和生成器

前言

此系列文章用于记录小萌新的ES6的学习经历如有什么错误或者不好的地方请各位大佬多多指教


一、迭代器(Iterator)

1.1.迭代器的作用

  • 为各种数据结构,提供一个统一的、简便的访问接口。
  • ES6提供了新的遍历命令for…of循环来消费Iterator 接口。
  • 任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
    即依次处理该数据结构的所有成员。

1.2.Iterator 的遍历过程

Iterator 的遍历过程

  • 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
  • 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
  • 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
  • 不断调用指针对象的next方法,直到它指向数据结构的结束位置。

Symbol.iterator属性

  • ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性。
  • 或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。

原生具备 Iterator 接口的数据结构

  • Array
  • Map
  • Set
  • String
  • TypedArray(类型化的数组)
  • 函数的 arguments 对象
  • NodeList 对象

代码如下(示例):

{
  let arr = ["a", "b", "c"];
  let iter = arr[Symbol.iterator]();
  console.log(iter.next()); //{ value: 'a', done: false }
  console.log(iter.next()); //{ value: 'b', done: false }
  console.log(iter.next()); //{ value: 'c', done: false }
  console.log(iter.next()); //{ value: undefined, done: true }
}

1.3.实现iterator接口的自定义类示例

代码如下(示例):

{
    class RangeIterator {
        constructor(start, stop, step) {
            this.value = start;
            this.stop = stop;
            this.step = step;
        }
        [Symbol.iterator]() {
            return this;
        }
        next() {
            let value = this.value;
            if (value < this.stop) {
                this.value += this.step;
                return { done: false, value: value };
            }
            return { done: true, value: undefined };
        }
    }
    function range(start, stop, step = 1) {
        return new RangeIterator(start, stop, step);
    }
    for (let value of range(0, 9, 2)) {
        console.log(value);
    }
    console.log([...range(1, 5)]); //0 2 4 6 8
}

通过此类可以创建如pythonrange一样的一个函数,用来产生自定义起始、结束、步长数组的函数。


二、生成器(Generator)

生成器主要是可以配合迭代器进行每一次next()做简化,提供了一种可以暂停执行的函数。yield表达式就是暂停标志。

2.1.生成器的运行逻辑

遍历器对象的next方法的运行逻辑

  • 遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
  • 下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
  • 如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
  • 如果该函数没有return语句,则返回的对象的value属性值为undefined。

代码如下(示例):

{
  let obj = {
    name1: "Tom",
    name2: "Jerry",
    name3: "Mickey",
    name4: "Miney",
    *[Symbol.iterator]() {
      yield this.name1;
      yield this.name2;
      yield this.name3;
    },
  };
  console.log(obj[Symbol.iterator]().next()); //{ value: 'Tom', done: false }
  console.log([...obj]); //[ 'Tom', 'Jerry', 'Mickey' ]
  for (let k of obj) {
    console.log(k); //Tom Jerry Mickey
  }
}
  • 可以看到在第一个log的输出中因为只调用了一次next()方法所以打印出了{ value: 'Tom', done: false }value为遍历输出的值,而done表示还没有遍历完这个对象。
  • 第二个log的输出因为使用了扩展运算符把obj进行展开到数组里面但是在生成器中只定义了三个yield所以遍历到name3的时候done的值就会为true从而结束遍历。

遍历器对象除了具有next方法,还可以具有return方法。

  • 如果for…of循环提前退出(通常是因为出错,或者有break语句),就会调用return方法。
  • 如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return方法。

代码如下(示例):

{
  function* helloWorldGenerator() {
    yield "hello";
    yield "world";
    return "ending";
  }
  let hw = helloWorldGenerator();
  console.log(hw.next()); //{ value: 'hello', done: false }
  console.log(hw.next()); //  { value: 'world', done: false }
  console.log(hw.next()); //  { value: 'ending', done: true }
  console.log(hw.next()); //  { value: undefined, done: true }
}

三、利用迭代器和生成器完成斐波拉契数列


    class Fib {
        constructor(value) {
            this.value = value;
            // this.oldsum = 0;
            // this.newsum = 1;
        }
        *[Symbol.iterator]() {
            let [a,b] = [0,1];
            while(true){
                [a,b] = [b, a+b];
                if(a>this.value){
                    return
                }
                yield a;
            }
        }
    }
    let fibs = new Fib(100);
    for (let f of fibs) {
        console.log(f);
    }
    /*
    1
	1
	2
	3
	5
	8
	13
	21
	34
	55
	89
	*/

此代码利用生成器在进行遍历的时候交换前两数列的顺序并且相加,然后再最后设置遍历到最后最大为剁手进行条件判断如果超过100则使用return结束遍历。


总结

本文主要讲述了ES6中的迭代器和生成器方面的知识,如果又不好的地方希望大家多多提意见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值