JavaScript高级程序设计笔记07 迭代器与生成器

迭代器与生成器

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 early
let counter3 = new Counter(5);
let [a, b] = counter3;
console.log( a );
console.log( b );
// Exiting early
// 1
// 2

console.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(); // foobar
generatorObject.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
// bar
g3 = 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,4
console.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 );
}
// foo

function* 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:  bar
for(const x of innerGeneratorFn()) {
   console.log( x );
}
// foo

class 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
posted @ 2022-10-11 12:01  beckyye  阅读(50)  评论(0编辑  收藏  举报