迭代器和生成器

60 阅读1分钟

21. 迭代器和生成器

1. 迭代器:

在JavaScript中,迭代器(Iterator)是一个对象,用于在可迭代的数据结构中遍历和访问每个元素,而不必暴露该数据结构的内部结构。很多数据结构都实现了可迭代接口:字符串、数组、MapSetargumentsNodeListDOM集合类型,可以使用Symbol.iterator方法获取它们的迭代器对象。

迭代器对象通常实现了一个next()方法,每次调用该方法将返回一个包含两个属性的对象:valuedone。其中,value属性表示集合中下一个要返回的元素的值,done属性表示是否已经到达集合的末尾。当done属性为true时,表示已经访问完所有元素。如:

let str = "hello"
let strIter = str[Symbol.iterator]();
console.log(strIter.next());//{value: 'h', done: false}
console.log(strIter.next());//{value: 'e', done: false}
console.log(strIter.next());//{value: 'l', done: false}
console.log(strIter.next());//{value: 'l', done: false}
console.log(strIter.next());//{value: 'o', done: false}
console.log(strIter.next());//{value: undefined, done: true}

let arr = [1,2,3]
let arrIter = arr[Symbol.iterator]();
console.log(arrIter.next());//{value: '1', done: false}
console.log(arrIter.next());//{value: '2', done: false}
console.log(arrIter.next());//{value: '3', done: false}
console.log(arrIter.next());//{value: undefined, done: true}

自定义可迭代对象

// 创建一个可迭代对象
const myObj = {
  data: [1, 2, 3],
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        if (index < this.data.length) {
          return { value: this.data[index++], done: false };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
};

const iterator = myObj[Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

2.生成器

在JavaScript中,生成器的形式是一个函数,函数名称前面加一个星号(*)表示它是一个生成器函数。只要可以定义函数的地方,就可以定义生成器。

// 生成器函数
function* generatorFn(){}

调用生成器函数会产成一个生成器对象,生成器对象也是迭代器,所以生成器对象也有next()方法,调用next方法会执行生成器函数中的代码,直到遇到yield关键字或者done状态为true

let gn = generatorFn()
console.log(gn);//generatorFn {<suspended>}
console.log(gn.next);//ƒ next() { [native code] }
console.log(gn.next());//{value: undefined, done: true}
function* generatorFn(){
  console.log("第一段代码~");
  yield "first end"

  console.log("第二段代码~");
  yield "second end"

  console.log("第三段代码~");
  return "123"
}
let gn = generatorFn()
console.log(gn.next());//第一段代码~ {value: 'first end', done: false}
console.log(gn.next());//第二段代码~ {value: 'second end', done: false}
console.log(gn.next());//第三段代码~ {value: '123', done: true}

next()方法可以传参数,这个参数会作为上一个yield语句的返回值

// next传值
function* compute(num){
  console.log(num);
  let n1 = yield num * 10
  console.log(n1);
  let n2 = yield n1 * 10
  console.log(n2);
  return n2
}
let numGn = compute(2)
console.log(numGn.next());//2  {value: 20, done: false} 
console.log(numGn.next(3));//3  {value: 30, done: false}
console.log(numGn.next(4));//4  {value: 4, done: true}