• JS高级 之 使用 Iterator - Generator


    目录

    一、迭代器

    1. 概念

    2. JavaSript中的迭代器

    3. 手写一个数组迭代器

    4. 优化一下,使其通用

    二、可迭代对象

    1. 概念

    2. 创建迭代器对象

    01 - 迭代对象中的数组

    02 - 迭代对象本身

    3. 原生可迭代对象 

    01 - 数组

    02 - set

    03 - arguments

    4. 可迭代对象的应用

    00 - 将对象变成可迭代对象 

    01 - 对象的展开

    02 - 使用set

    03 - 使用Promise

    5. 自定义类的迭代

    6. 迭代器的中断

    三、生成器

    1. 生成器函数

    2. 生成器函数的基本使用

    3. 生成器函数yield来返回值 

    4. 生成器函数中遇到return

    5.  生成器函数进行参数传递

    6.  生成器函数提前结束

    01 - 使用return

    02 - 抛出异常

    四、生成器替代迭代器 

    1. 使用 yield 重构数组迭代器

    2. 使用生成器函数生成某个范围的值

    3. 使用 yield*

    01 - 使用 yield* 重构数组迭代器

    02 - 使用 yield* 使对象变成可迭代对象 

    03 - 使用 yield* 重构自定义类的迭代


    一、迭代器

    1. 概念

    迭代器(iterator),使用户在容器对象(container,例如链表或数组)上遍访的对象,使用该接口无需关心对象的内部实现细节。

    • 其行为像数据库中的光标,迭代器最早出现在1974年设计的CLU编程语言中
    • 在各种编程语言的实现中,迭代器的实现方式各不相同,但是基本都有迭代器,比如Java、Python等

    从迭代器的定义我们可以看出来,迭代器是帮助我们对某个数据结构进行遍历的对象

    2. JavaSript中的迭代器

    在JavaScript中,迭代器也是一个具体的对象

    这个对象需要符合迭代器协议(iterator protocol):

    • 迭代器协议定义了产生一系列值(无论是有限还是无限个)的标准方式
    • 在JavaScript中这个标准就是一个特定的next方法

    next方法有如下的要求:

    • 一个无参数或者一个参数的函数,返回一个应当拥有以下两个属性的对象,必须返回对象
    • done(boolean)
      • 如果迭代器可以产生序列中的下一个值,则为 false。(这等价于没有指定 done 这个属性。)
      • 如果迭代器已将序列迭代完毕,则为 true。这种情况下,value 是可选的,如果它依然存在,即为迭代结束之后的默认返回值
    • value
      • 迭代器返回的任何 JavaScript 值。done 为 true 时可省略

    3. 手写一个数组迭代器

    1. const arr = ['a', 'b', 'c', 'd'];
    2. // 创建一个arr的迭代器对象
    3. // 1. 创建一个索引
    4. let index = 0;
    5. const arrIterator = {
    6. // 2. 必须实现next方法
    7. next() {
    8. // 没有迭代完成
    9. if (index < arr.length) {
    10. // 3. 返回两个参数 done -> 是否完成 value : 值 执行完后index++
    11. return { done: false, value: arr[index++] };
    12. } else {
    13. // 迭代完成 value也可不写
    14. return { done: true, value: undefined };
    15. }
    16. }
    17. };
    18. console.log(arrIterator.next()); // { done: false, value: 'a' }
    19. console.log(arrIterator.next()); // { done: false, value: 'b' }
    20. console.log(arrIterator.next()); // { done: false, value: 'c' }
    21. console.log(arrIterator.next()); // { done: false, value: 'd' }
    22. console.log(arrIterator.next()); // { done: true, value: undefined }
    23. console.log(arrIterator.next()); // { done: true, value: undefined }

    4. 优化一下,使其通用

    1. const arr = ['a', 'b', 'c', 'd'];
    2. const nums = [11, 22, 33];
    3. function createArrayIterator(arr) {
    4. let index = 0;
    5. // 1. 返回这个迭代器对象
    6. return {
    7. // 2. 必须实现next方法
    8. next() {
    9. // 3. 返回两个参数 done -> 是否完成 value : 值 执行完后index++
    10. return { done: index >= arr.length, value: arr[index++] };
    11. }
    12. };
    13. }
    14. const arrIterator = createArrayIterator(arr);
    15. console.log(arrIterator.next()); // { done: false, value: 'a' }
    16. console.log(arrIterator.next()); // { done: false, value: 'b' }
    17. console.log(arrIterator.next()); // { done: false, value: 'c' }
    18. console.log(arrIterator.next()); // { done: false, value: 'd' }
    19. console.log(arrIterator.next()); // { done: true, value: undefined }
    20. console.log(arrIterator.next()); // { done: true, value: undefined }
    21. const numsIterator = createArrayIterator(nums);
    22. console.log(numsIterator.next()); // { done: false, value: 11 }
    23. console.log(numsIterator.next()); // { done: false, value: 22 }
    24. console.log(numsIterator.next()); // { done: false, value: 33 }
    25. console.log(numsIterator.next()); // { done: true, value: undefined }
    26. console.log(numsIterator.next()); // { done: true, value: undefined }
    27. console.log(numsIterator.next()); // { done: true, value: undefined }

    二、可迭代对象

    1. 概念

    可迭代对象 : 

    • 它和迭代器是不同的概念
    • 当一个对象实现了iterable protocol协议时,它就是一个可迭代对象
    • 这个对象的要求是必须实现 @@iterator 方法,在代码中我们使用 Symbol.iterator 访问该属性

    转变为可迭代对象的好处 : 

    • 当一个对象变成一个可迭代对象的时候,就可以进行某些迭代操作
    • 比如 for...of 操作时,其实就会调用它的 @@iterator 方法

    2. 创建迭代器对象

    01 - 迭代对象中的数组

    1. // 一、拥有[Symbol.iterator]方法, 并且内部实现了迭代器的对象,就称之为 => 可迭代对象
    2. const obj = {
    3. name: 'coder',
    4. // 1. 测试数据
    5. arr: ['a', 'b', 'c', 'd'],
    6. // 2. 必须有这个属性名实现的方法
    7. [Symbol.iterator]() {
    8. // 3. 内部实现一个迭代器
    9. let index = 0;
    10. // 4. 返回这个迭代器
    11. return {
    12. next: () => {
    13. // 这里为了使用this,需要使用箭头函数,你懂的,找到外层的this
    14. return { done: index >= this.arr.length, value: this.arr[index++] };
    15. }
    16. };
    17. }
    18. };
    19. // 二、使用迭代器
    20. const objIterator = obj[Symbol.iterator]();
    21. console.log(objIterator.next()); // { done: false, value: 'a' }
    22. console.log(objIterator.next()); // { done: false, value: 'b' }
    23. console.log(objIterator.next()); // { done: false, value: 'c' }
    24. console.log(objIterator.next()); // { done: false, value: 'd' }
    25. console.log(objIterator.next()); // { done: true, value: undefined }
    26. console.log(objIterator.next()); // { done: true, value: undefined }
    27. console.log(objIterator.next()); // { done: true, value: undefined }
    28. // 三、可迭代对象可以使用for...of循环
    29. // 返回的值,就是跌打器中的各个有值的value
    30. for (const item of obj) {
    31. console.log(item); // a b c d
    32. }

    02 - 迭代对象本身

    1. // 一、拥有[Symbol.iterator]方法, 并且内部实现了迭代器的对象,就称之为 => 可迭代对象
    2. /*
    3. 1.必须实现一个特定的函数: [Symbol.iterator]
    4. 2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
    5. */
    6. const obj = {
    7. name: 'coder',
    8. age: 18,
    9. info: ['abc', 'acb', 'ope'],
    10. // 2. 必须有这个属性名实现的方法
    11. [Symbol.iterator]() {
    12. // 3. 内部实现一个迭代器
    13. let index = 0;
    14. const entries = Object.entries(this);
    15. // 4. 返回这个迭代器
    16. return {
    17. next: () => {
    18. if (index < entries.length) {
    19. const [key, value] = entries[index++];
    20. return { done: false, value: { key, value } };
    21. } else {
    22. return { done: true };
    23. }
    24. }
    25. };
    26. }
    27. };
    28. // 二、使用迭代器
    29. const objIterator = obj[Symbol.iterator]();
    30. console.log(objIterator.next()); // { done: false, value: { key: 'name', value: 'coder' } }
    31. console.log(objIterator.next()); // { done: false, value: { key: 'age', value: 18 } }
    32. console.log(objIterator.next()); // { done: false, value: { key: 'info', value: [ 'abc', 'acb', 'ope' ] } }
    33. console.log(objIterator.next()); // { done: true }
    34. console.log(objIterator.next()); // { done: true }
    35. // 三、可迭代对象可以使用for...of循环
    36. // 返回的值,就是跌打器中的各个有值的value
    37. // 本质就是调用迭代器的next
    38. for (const item of obj) {
    39. console.log(item);
    40. /**
    41. * { key: 'name', value: 'coder' }
    42. * { key: 'age', value: 18 }
    43. * { key: 'info', value: [ 'abc', 'acb', 'ope' ] }
    44. */
    45. }

    3. 原生可迭代对象 

    很多原生对象已经实现了可迭代协议,会生成一个迭代器对象,例如 : 

    String、Array、Map、Set、arguments对象、NodeList集合

    01 - 数组

    1. // 数组
    2. const names = ['abc', 'cba', 'nba'];
    3. // 1. 使用[Symbol.iterator]方法
    4. const namesIterator = names[Symbol.iterator]();
    5. console.log(namesIterator.next()); // {value: 'abc', done: false}
    6. console.log(namesIterator.next()); // {value: 'cba', done: false}
    7. console.log(namesIterator.next()); // {value: 'nba', done: false}
    8. console.log(namesIterator.next()); // {value: undefined, done: true}
    9. // 2. 使用for..of..
    10. for (const name of names) {
    11. console.log(name); // abc cba nba
    12. }

    02 - set

    1. // Set
    2. const set = new Set(['abc', 'cba', 'nba']);
    3. // 1. 使用[Symbol.iterator]方法
    4. const setIterator = set[Symbol.iterator]();
    5. console.log(setIterator.next()); // {value: 'abc', done: false}
    6. console.log(setIterator.next()); // {value: 'cba', done: false}
    7. console.log(setIterator.next()); // {value: 'nba', done: false}
    8. console.log(setIterator.next()); // {value: undefined, done: true}
    9. // 2. 使用for..of..
    10. for (const item of set) {
    11. console.log(item); // abc cba nba
    12. }

    03 - arguments

    1. // arguments
    2. function foo() {
    3. const arguIterator = arguments[Symbol.iterator]();
    4. // 1. 使用[Symbol.iterator]方法
    5. console.log(arguIterator.next()); // {value: 111, done: false}
    6. console.log(arguIterator.next()); // {value: 222, done: false}
    7. console.log(arguIterator.next()); // {value: 333, done: false}
    8. console.log(arguIterator.next()); // {value: undefined, done: true}
    9. // 2. 使用for..of..
    10. for (const arg of arguments) {
    11. console.log(arg); // 111 222 333
    12. }
    13. }
    14. foo(111, 222, 333);

    4. 可迭代对象的应用

    JavaScript中语法:

    for ...of、展开语法、yield*、解构赋值、...

    注 : 对象可以在对象中展开,不是因为可迭代对象,是js引擎专门加上的,以前是只有可迭代对象才能展开

    创建一些对象时:

    new Map([Iterable])、new WeakMap([iterable])、new Set([iterable])、new WeakSet([iterable])、...

    一些方法的调用:

    Promise.all(iterable)、Promise.race(iterable)、Array.from(iterable)、...

    都是传入的可迭代对象,也就是说,只要是可迭代对象,这些场景都能使用

    00 - 将对象变成可迭代对象 

    1. // 1. 使得info对象编程可迭代对象
    2. const info = {
    3. name: 'coder',
    4. age: 18,
    5. height: 1.88,
    6. // 2. 设定返回的值为对象的value值
    7. [Symbol.iterator]: function () {
    8. const values = Object.values(this);
    9. let index = 0;
    10. const iterator = {
    11. next: function () {
    12. if (index < values.length) {
    13. return { done: false, value: values[index++] };
    14. } else {
    15. return { done: true };
    16. }
    17. }
    18. };
    19. return iterator;
    20. }
    21. };

    01 - 对象的展开

    1. function foo(arg1, arg2, arg3) {
    2. console.log(arg1, arg2, arg3); // coder 18 1.88
    3. }
    4. // 3. 展开运算符可以展开可迭代对象,这里自定义了
    5. foo(...info);

    02 - 使用set

    1. // set中, 也是传入的可迭代对象
    2. // 1. 传入数组,因为数组是可迭代对象
    3. const set = new Set(['aaa', 'bbb', 'ccc']);
    4. console.log(set); // Set(3) {'aaa', 'bbb', 'ccc'}
    5. // 2. 传入字符串,因为字符是可迭代对象
    6. const set2 = new Set('abc');
    7. console.log(set2); // Set(3) {'a', 'b', 'c'}
    8. // 3. 传入自定义的可迭代对象
    9. const set3 = new Set(info);
    10. console.log(set3); // Set(3) {'coder', 18, 1.88}

    03 - 使用Promise

    1. // 3.Promise.all中, 也是传入的可迭代对象
    2. const p1 = Promise.resolve('aaa');
    3. const p2 = Promise.resolve('bbb');
    4. const p3 = Promise.resolve('ccc');
    5. const pSet = new Set();
    6. pSet.add(p1);
    7. pSet.add(p2);
    8. pSet.add(p3);
    9. // 传入set对象,因为set也是可迭代对象
    10. Promise.all(pSet).then((res) => {
    11. console.log(res); //  ['aaa', 'bbb', 'ccc']
    12. });

    5. 自定义类的迭代

    使得类创建出来的对象默认是可迭代

    1. // 1. 定义一个类
    2. class Person {
    3. constructor(name, age, height) {
    4. this.name = name;
    5. this.age = age;
    6. this.height = height;
    7. }
    8. // 2. 定义[Symbol.iterator]实例方法,让所有实例都能访问
    9. [Symbol.iterator]() {
    10. let index = 0;
    11. const entries = Object.entries(this);
    12. return {
    13. next() {
    14. if (index < entries.length) {
    15. const [key, value] = entries[index++];
    16. return { done: false, value: { key, value } };
    17. } else {
    18. return { done: true };
    19. }
    20. }
    21. };
    22. }
    23. }
    24. // 3. 创建实例对象,且生成的对象都为可迭代对象
    25. const p1 = new Person('coder', 18, 1.88);
    26. const p2 = new Person('star', 16, 1.66);
    27. for (const item of p1) {
    28. /**
    29. * { key: 'name', value: 'coder' }
    30. * { key: 'age', value: 18 }
    31. * { key: 'height', value: 1.88 }
    32. */
    33. console.log(item);
    34. }
    35. for (const item of p2) {
    36. /**
    37. * { key: 'name', value: 'star' }
    38. * { key: 'age', value: 16 }
    39. * { key: 'height', value: 1.66 }
    40. */
    41. console.log(item);
    42. }

    6. 迭代器的中断

    迭代器在某些情况下会在没有完全迭代的情况下中断 : 

    • 比如遍历的过程中通过break、return、throw中断了循环操作
    • 比如在解构的时候,没有解构所有的值
    • 如果想要监听中断的话,可以添加return方法
    1. // 1. 定义一个类
    2. class Person {
    3. constructor(name, age, height) {
    4. this.name = name;
    5. this.age = age;
    6. this.height = height;
    7. }
    8. // 2. 定义[Symbol.iterator]实例方法,让所有实例都能访问
    9. [Symbol.iterator]() {
    10. let index = 0;
    11. const entries = Object.entries(this);
    12. return {
    13. next() {
    14. if (index < entries.length) {
    15. const [key, value] = entries[index++];
    16. return { done: false, value: { key, value } };
    17. } else {
    18. return { done: true };
    19. }
    20. },
    21. // 3. 如果中断了,回调用该方法
    22. return() {
    23. console.log('中断了');
    24. // 记得返回一个对象,否则会报错。迭代器都是要返回一个对象的
    25. return { done: true };
    26. }
    27. };
    28. }
    29. }
    30. // 4. 创建实例对象,且生成的对象都为可迭代对象
    31. const p = new Person('coder', 18, 1.88);
    32. for (const { key, value } of p) {
    33. console.log(value); // coder 18
    34. if (value === 18) {
    35. break; // 中断了
    36. }
    37. }

    三、生成器

    生成器 : ES6中新增的一种函数控制、使用的方案,它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行等

    1. 生成器函数

    生成器函数也是一个函数,但是和普通的函数有一些区别:

    • 首先,生成器函数需要在function的后面加一个符号 => *
    • 其次,生成器函数可以通过yield关键字来控制函数的执行流程
    • 最后,生成器函数的返回值是一个Generator(生成器)
      • 生成器事实上是一种特殊的迭代器
      • MDN:Instead, they return a special type of iterator, called a Generator 

    2. 生成器函数的基本使用

    1. /*
    2. 生成器函数:
    3. 1.function后面会跟上符号: *
    4. 2.代码的执行可以被yield控制
    5. 3.生成器函数默认在执行时, 返回一个生成器对象
    6. * 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作
    7. * 当遇到yield时, 就会中断执行
    8. */
    9. // 1.定义了一个生成器函数
    10. function* foo() {
    11. console.log(111);
    12. console.log(222);
    13. yield;
    14. console.log(333);
    15. console.log(444);
    16. yield;
    17. console.log(555);
    18. console.log(666);
    19. yield;
    20. console.log('函数结束运行');
    21. }
    22. // 2.调用生成器函数, 返回一个 生成器对象
    23. const generator = foo();
    24. // 3. 调用next方法
    25. // 执行到第一个yield,并且暂停
    26. generator.next(); // 111 222
    27. // 执行到第二个yield,并且暂停
    28. generator.next(); // 333 444
    29. // 执行到第三个yield,并且暂停
    30. generator.next(); // 555 666
    31. // 执行到第三个yield,并且暂停剩下的函数
    32. generator.next(); // '函数结束运行'

    3. 生成器函数yield来返回值 

    1. // 1.定义了一个生成器函数
    2. function* foo() {
    3. console.log(111);
    4. console.log(222);
    5. // 定义返回值
    6. yield 'first';
    7. console.log(333);
    8. console.log(444);
    9. yield ['secode'];
    10. console.log(555);
    11. console.log(666);
    12. yield { key: 'three' };
    13. console.log('函数结束运行');
    14. }
    15. // 2.调用生成器函数, 返回一个 生成器对象
    16. const generator = foo();
    17. // 3. 调用next方法
    18. console.log(generator.next());
    19. console.log(generator.next());
    20. console.log(generator.next());
    21. console.log(generator.next());
    22. /**
    23. * 打印结果
    24. * 111
    25. 222
    26. { value: 'first', done: false }
    27. 333
    28. 444
    29. { value: [ 'secode' ], done: false }
    30. 555
    31. 666
    32. { value: { key: 'three' }, done: false }
    33. '函数结束运行'
    34. { value: undefined, done: true }
    35. */

    4. 生成器函数中遇到return

    1. // 1.定义了一个生成器函数
    2. function* foo() {
    3. console.log(111);
    4. console.log(222);
    5. // 定义返回值
    6. yield 'first';
    7. console.log(333);
    8. console.log(444);
    9. // 遇到return,直接返回
    10. return ['secode'];
    11. console.log(555);
    12. console.log(666);
    13. yield { key: 'three' };
    14. console.log('函数结束运行');
    15. }
    16. // 2.调用生成器函数, 返回一个 生成器对象
    17. const generator = foo();
    18. // 3. 调用next方法
    19. console.log(generator.next());
    20. console.log(generator.next());
    21. console.log(generator.next());
    22. console.log(generator.next());
    23. /**
    24. * 打印结果
    25. * 111
    26. 222
    27. { value: 'first', done: false }
    28. 333
    29. 444
    30. { value: [ 'secode' ], done: true }
    31. { value: undefined, done: true }
    32. { value: undefined, done: true }
    33. */

    5.  生成器函数进行参数传递

    在调用next函数的时候,可以给它传递参数,那么这个参数会作为上一个yield语句的返回值

     

    注意:也就是说我们是为本次的函数代码块执行提供了一个值

    1. // 1.定义了一个生成器函数
    2. function* foo(msg1) {
    3. console.log(111, msg1);
    4. console.log(222, msg1);
    5. // 这里接受第二个next
    6. const msg2 = yield 'first';
    7. console.log(333, msg2);
    8. console.log(444, msg2);
    9. // 这里接受第三个next
    10. const msg3 = yield ['secode'];
    11. console.log(555, msg3);
    12. console.log(666, msg3);
    13. // 这里接受第四个next
    14. const msg4 = yield { key: 'three' };
    15. console.log('函数结束运行', msg4);
    16. }
    17. // 1. 第一次传的参数,一般写在这
    18. const generator = foo('next1');
    19. console.log(generator.next());
    20. // 2. 第二次传的参数,注意,接受的地方为第一个yield
    21. console.log(generator.next('next2'));
    22. console.log(generator.next('next3'));
    23. console.log(generator.next('next4'));
    24. /**
    25. * 111 next1
    26. 222 next1
    27. { value: 'first', done: false }
    28. 333 next2
    29. 444 next2
    30. { value: [ 'secode' ], done: false }
    31. 555 next3
    32. 666 next3
    33. { value: { key: 'three' }, done: false }
    34. 函数结束运行 next4
    35. { value: undefined, done: true }
    36. */

    6.  生成器函数提前结束

    01 - 使用return

    1. function* foo(name1) {
    2. console.log('执行内部代码:1111', name1);
    3. console.log('执行内部代码:2222', name1);
    4. const name2 = yield 'aaaa';
    5. console.log('执行内部代码:3333', name2);
    6. console.log('执行内部代码:4444', name2);
    7. const name3 = yield 'bbbb';
    8. // return "bbbb"
    9. console.log('执行内部代码:5555', name3);
    10. console.log('执行内部代码:6666', name3);
    11. yield 'cccc';
    12. console.log('最后一次执行');
    13. return undefined;
    14. }
    15. const generator = foo('next1');
    16. // generator.return提前结束函数
    17. console.log(generator.next());
    18. console.log(generator.return('next2'));
    19. // done为true,不会执行内部的代码了
    20. console.log('-------------------');
    21. console.log(generator.next('next3'));
    22. console.log(generator.next('next4'));
    23. /**
    24. *
    25. * 执行内部代码:1111 next1
    26. 执行内部代码:2222 next1
    27. {value: 'aaaa', done: false}
    28. {value: 'next2', done: true}
    29. -------------------
    30. {value: undefined, done: true}
    31. {value: undefined, done: true}
    32. *
    33. */

    02 - 抛出异常

    1. function* foo(name1) {
    2. console.log('执行内部代码:1111', name1);
    3. console.log('执行内部代码:2222', name1);
    4. const name2 = yield 'aaaa';
    5. console.log('执行内部代码:3333', name2);
    6. console.log('执行内部代码:4444', name2);
    7. const name3 = yield 'bbbb';
    8. // return "bbbb"
    9. console.log('执行内部代码:5555', name3);
    10. console.log('执行内部代码:6666', name3);
    11. yield 'cccc';
    12. console.log('最后一次执行');
    13. return undefined;
    14. }
    15. const generator = foo('next1');
    16. // generator.throw向函数抛出一个异常
    17. console.log(generator.next());
    18. console.log(generator.throw(new Error('next2 throw error')));
    19. // 也立即终止了
    20. console.log('-------------------');
    21. console.log(generator.next('next3'));
    22. console.log(generator.next('next4'));
    23. /**
    24. * 执行内部代码:1111 next1
    25. 执行内部代码:2222 next1
    26. {value: 'aaaa', done: false}
    27. 报错,这里没有捕获,可以用try catch
    28. */

    四、生成器替代迭代器 

    生成器是一种特殊的迭代器,那么在某些情况下可以使用生成器来替代迭代器

    1. 使用 yield 重构数组迭代器

    1. const arr = ['a', 'b', 'c', 'd'];
    2. const nums = [11, 22, 33];
    3. // 1. 创建生成器函数
    4. function* createArrayIterator(arr) {
    5. for (let i = 0; i < arr.length; i++) {
    6. // 完美!
    7. yield arr[i];
    8. }
    9. }
    10. // 2. 创建生成器,生成器就是一个特殊的迭代器
    11. const arrIterator = createArrayIterator(arr);
    12. console.log(arrIterator.next()); // { done: false, value: 'a' }
    13. console.log(arrIterator.next()); // { done: false, value: 'b' }
    14. console.log(arrIterator.next()); // { done: false, value: 'c' }
    15. console.log(arrIterator.next()); // { done: false, value: 'd' }
    16. console.log(arrIterator.next()); // { done: true, value: undefined }
    17. console.log(arrIterator.next()); // { done: true, value: undefined }
    18. // 3. 创建生成器,生成器就是一个特殊的迭代器
    19. const numsIterator = createArrayIterator(nums);
    20. console.log(numsIterator.next()); // { done: false, value: 11 }
    21. console.log(numsIterator.next()); // { done: false, value: 22 }
    22. console.log(numsIterator.next()); // { done: false, value: 33 }
    23. console.log(numsIterator.next()); // { done: true, value: undefined }
    24. console.log(numsIterator.next()); // { done: true, value: undefined }
    25. console.log(numsIterator.next()); // { done: true, value: undefined }

    2. 使用生成器函数生成某个范围的值

    1. // [3, 9)
    2. function* createRangeGenerator(start, end) {
    3. for (let i = start; i < end; i++) {
    4. yield i;
    5. }
    6. }
    7. const rangeGen = createRangeGenerator(3, 9);
    8. console.log(rangeGen.next()); // {value: 3, done: false}
    9. console.log(rangeGen.next()); // {value: 4, done: false}
    10. console.log(rangeGen.next()); // {value: 5, done: false}
    11. console.log(rangeGen.next()); // {value: 6, done: false}
    12. console.log(rangeGen.next()); // {value: 7, done: false}
    13. console.log(rangeGen.next()); // {value: 8, done: false}
    14. console.log(rangeGen.next()); // {value: undefined, done: true}

    3. 使用 yield*

    还可以使用yield*来生产一个可迭代对象

    这个时候的 yield* 是一种yield的语法糖,只不过会依次迭代这个可迭代对象,每次迭代其中的一个值

    01 - 使用 yield* 重构数组迭代器

    1. const arr = ['a', 'b', 'c', 'd'];
    2. const nums = [11, 22, 33];
    3. // 1. 创建生成器函数
    4. function* createArrayIterator(arr) {
    5. // 一行代码搞定
    6. yield* arr;
    7. }
    8. // 2. 创建生成器,生成器就是一个特殊的迭代器
    9. const arrIterator = createArrayIterator(arr);
    10. console.log(arrIterator.next()); // { done: false, value: 'a' }
    11. console.log(arrIterator.next()); // { done: false, value: 'b' }
    12. console.log(arrIterator.next()); // { done: false, value: 'c' }
    13. console.log(arrIterator.next()); // { done: false, value: 'd' }
    14. console.log(arrIterator.next()); // { done: true, value: undefined }
    15. console.log(arrIterator.next()); // { done: true, value: undefined }
    16. // 3. 创建生成器,生成器就是一个特殊的迭代器
    17. const numsIterator = createArrayIterator(nums);
    18. console.log(numsIterator.next()); // { done: false, value: 11 }
    19. console.log(numsIterator.next()); // { done: false, value: 22 }
    20. console.log(numsIterator.next()); // { done: false, value: 33 }
    21. console.log(numsIterator.next()); // { done: true, value: undefined }
    22. console.log(numsIterator.next()); // { done: true, value: undefined }
    23. console.log(numsIterator.next()); // { done: true, value: undefined }

    02 - 使用 yield* 使对象变成可迭代对象 

    1. // 1. 可迭代对象
    2. const info = {
    3. name: 'coder',
    4. age: 18,
    5. info: [1, 2, 3],
    6. *[Symbol.iterator]() {
    7. yield* Object.entries(this);
    8. }
    9. };
    10. // 2. 获取生成器对象
    11. const infoIterator = info[Symbol.iterator]();
    12. // 3. 调用next方法
    13. console.log(infoIterator.next()); // { value: [ 'name', 'coder' ], done: false }
    14. console.log(infoIterator.next()); // { value: [ 'age', 18 ], done: false }
    15. console.log(infoIterator.next()); // { value: [ 'info', [ 1, 2, 3 ] ], done: false }
    16. console.log(infoIterator.next()); // { value: undefined, done: true }

    03 - 使用 yield* 重构自定义类的迭代

    1. // 1. 定义一个类
    2. class Person {
    3. constructor(name, age, height) {
    4. this.name = name;
    5. this.age = age;
    6. this.height = height;
    7. }
    8. // 2. 定义[Symbol.iterator]实例方法,让所有实例都能访问
    9. *[Symbol.iterator]() {
    10. yield* Object.entries(this);
    11. }
    12. }
    13. // 3. 创建实例对象,且生成的对象都为可迭代对象
    14. const p1 = new Person('coder', 18, 1.88);
    15. const p2 = new Person('star', 16, 1.66);
    16. for (const [key, value] of p1) {
    17. /**
    18. * name coder
    19. * age 18
    20. * height 1.88
    21. */
    22. console.log(key, value);
    23. }
    24. for (const [key, value] of p2) {
    25. /**
    26. * name star
    27. * age 16
    28. * height 1.66
    29. */
    30. console.log(key, value);
    31. }
    32. const p1Iterator = p1[Symbol.iterator]();
    33. console.log(p1Iterator.next()); // { value: [ 'name', 'coder' ], done: false }
    34. console.log(p1Iterator.next()); // { value: [ 'age', 18 ], done: false }
    35. console.log(p1Iterator.next()); // { value: [ 'height', 1.88 ], done: false }
    36. console.log(p1Iterator.next()); // { value: undefined, done: true }
    37. console.log(p1Iterator.next()); // { value: undefined, done: true }

  • 相关阅读:
    go实现N个协程交替顺序打印自然数的详细解释
    涨姿势了,有意思的气泡 Loading 效果
    Leetcode 2895. Minimum Processing Time
    Rflysim | 传感器标定与测量实验二
    dp转自动机:1017T4
    ArcObjects SDK开发 007 自定义App-Command-Tool框架
    ts装饰器保存this指向
    debug技巧之使用arthas调试
    windows 安裝字體Font
    seata-分布式事务
  • 原文地址:https://blog.csdn.net/a15297701931/article/details/126240700