迭代器与生成器

1.迭代

重复屡次执行一段程序,(有明确的终止条件)

迭代器、生成器 ES6

  • 计数循环(for):最简略的迭代

    迭代次数、迭代每次执行的操作 (程序已知)

  • 古早迭代(有序->数组):①必须数组,需援用数组自身;②递增索引的形式
  • 通用迭代(ES5):forEach

    • 长处:不需援用数组本身;不需索引
    • 毛病:只限数组间接调用,不能手动终止

2. 迭代器模式

内置可迭代类型:

String、Array、Map、Set、arguments对象、NodeList等DOM汇合类型

  1. (迭代的自我辨认)有默认迭代器属性,键为Symbol.iterator,值为迭代器工厂函数
  2. (创立Iterator对象的能力)迭代器工厂函数返回【实现Iterator接口的对象】

    即蕴含键为next的属性、可能也蕴含键为return的属性

主动调用默认迭代器工厂函数来生成迭代器的操作:

for-of、数组解构、扩大操作符

Array.from(...)、new Set(...)、new Map(...)

Promise.all(...)、Promise.race(...)

yield* ...

Iterator保护一个指向可迭代对象的援用,会阻止垃圾回收。

每个内置可迭代对象的默认迭代器函数所产生的迭代器,也有本人的默认迭代器函数,返回指向本身(并未严格实现Iterable接口,默认迭代器函数不能创立新的迭代器)

class Counter {   constructor(limit) {      this.limit = limit;   }   [Symbol.iterator]() {      let count = 1,         o = this;      return {         next() {            if( count <= o.limit) {               return {                  done: false,                  value: count++               };            } else {               return {                  done: true               };            }         },         return() {            console.log( 'Exiting early' );            return {               done: true            };         }      }   }}let counter1 = new Counter(5);for (let i of counter1) {   if(i > 2) {      break;   }   console.log( i );}// 1// 2// Exiting earlylet counter3 = new Counter(5);let [a, b] = counter3;console.log( a );console.log( b );// Exiting early// 1// 2console.log( "//======= 数组的迭代器不能敞开" );let a1 = [1, 2, 3, 4, 5];let iter = a1[Symbol.iterator]();for (let i of iter) {   console.log( i );   if(i > 2) {      break;   }}for (let i of iter) {   console.log( i );}// 1// 2// 3// 4// 5

3. 生成器 generator

函数加前缀*号(箭头函数不行)——>生成器函数

/*Function generator() {  constructor() {    this = {      next() {        // ...      }    }    return this;  }  [Symbol.iterator]() {    return this;  }}*/let g = generator();g === g[Symbol.iterator]

应用场景(yield):

  1. 生成器对象作为可迭代对象(有默认[Symbol.iterator]为键的属性,无实现创立新迭代器的工厂函数)
  2. yield实现输入输出

    给next办法传参,参数会被当作上一个yield操作的后果值

  3. 产生可迭代对象

    yield* 可迭代对象

    yield*操作的后果值为 Iterable对象遍历到done为true时的value属性的值

  4. 实现递归 yield*(function* + yield*)

    可将递归后果包装成一个生成器对象(实现Iterator接口)

其余:

  • 生成器函数能够作为默认迭代器(工厂函数)

    产生->生成器对象(实现Iterator接口)

  • 生成器对象有API throw()

    生成器函数外部解决,可持续——>跳过当下的yield操作(去到下一个yield);没解决,就迭代终止。

function *generatorFn() {   return 'foo';}let generatorObject = generatorFn();console.log( generatorObject );console.log( generatorObject.next() );// Object [Generator] {}         generatorFn {<suspended>}// { value: 'foo', done: true }  {value: "foo", done: true}function *generatorFn2() {   console.log( 'foobar' );}generatorObject = generatorFn2();generatorObject.next(); // foobargeneratorObject.next();function* generatorFn3() {   yield 'foo';   yield 'bar';   return 'baz';}let g3 = generatorFn3();console.log( g3.next() );console.log( g3.next() );console.log( g3.next() );// { value: 'foo', done: false }// { value: 'bar', done: false }// { value: 'baz', done: true }g3 = generatorFn3();for(const x of g3) {   console.log( x );}// foo// barg3 = generatorFn2();for(const x of g3) {   console.log( x );}// foobar
class Node {   constructor(id) {      this.id = id;      this.neighbors = new Set();   }   connect(node) {      if (node !== this) {         this.neighbors.add( node );         node.neighbors.add( this );      }   }}class RandomGraph {   constructor(size) {      this.nodes = new Set();      for (let i = 0; i< size; ++ i) {         this.nodes.add( new Node(i) );      }      const threshold = 1 / size;      for (const x of this.nodes) {         for (const y of this.nodes) {            if (Math.random() < threshold) {               x.connect( y );            }         }      }   }   print() {      for (const node of this.nodes) {         const ids = [...node.neighbors].map(n => n.id).join(',');         console.log( `${node.id}: ${ids}` );      }   }   // 整张图是否连通   isConnected() {      const visitedNodes = new Set();      function *traverse(nodes) {         for (const node of nodes) {            if (!visitedNodes.has(node)) {               yield node;               yield* traverse(node.neighbors);            }         }      }      // 获得汇合中的第一个节点      const firstNode = this.nodes[Symbol.iterator]().next().value;      // 应用递归生成器迭代每个节点      for (const node of traverse([firstNode])) {         visitedNodes.add(node);      }      // function traverse(nodes) {      //     for (const node of nodes) {      //        if (!visitedNodes.has(node)) {      //           visitedNodes.add(node);      //           traverse(node.neighbors);      //        }      //     }      // }      return visitedNodes.size === this.nodes.size;   }}const g = new RandomGraph(6);g.print();// 0: 1,2// 1: 0,5// 2: 0// 3: // 4: 5// 5: 1,4console.log( g.isConnected() );console.log( '实现输入输出1===========' )function *generatorFn(initial) {   // console.log( initial );   console.log( yield 1 );   console.log( yield 2 );   return yield 3;}let genObj = generatorFn('foo');console.log( genObj.next('bar') );console.log( genObj.next('baz') );console.log( genObj.next('qux') ); console.log( genObj.next() );// { value: 1, done: false }// baz// { value: 2, done: false }// qux// { value: 3, done: false }// { value: undefined, done: true }console.log( '实现输入输出2===========' )function *generatorFn2() {   return yield 'foo';}let genObj2 = generatorFn2();console.log( genObj2.next() );console.log( genObj2.next('bar') );console.log( genObj2.next('test') );// { value: 'foo', done: false }// { value: 'bar', done: true } // 相当于给done的时候的value赋值?// { value: undefined, done: true }for (const x of generatorFn2()) {   console.log( x );}// foofunction* zeroes(n) {   while(n--) {      yield 0;   }}console.log( Array.from(zeroes(8)) );function *innerGeneratorFn() {   yield 'foo';   return 'bar';}function *outerGeneratorFn() {   console.log('iter value: ', yield* innerGeneratorFn());}for(const x of outerGeneratorFn()) {   console.log( 'value: ', x );}// value:  foo// iter value:  barfor(const x of innerGeneratorFn()) {   console.log( x );}// fooclass Foo {   constructor() {      this.values = [1, 2, 3];   }   * [Symbol.iterator]() {      yield* this.values;   }   // [Symbol.iterator]() {   //     let i = 0, len = this.values.length, o = this;   //     return {   //        next() {   //           return {   //              value: o.values[i++],   //              done: i > len   //           }   //        }   //     }   // }}const f = new Foo();for(const x of f) {   console.log( x );}// 1// 2// 3