likes
comments
collection
share

ES6 的迭代器和生成器是什么

作者站长头像
站长
· 阅读数 37

生成器

生成器是创建迭代器的函数。生成器函数由 function 关键字和之后的星号(*)标识,同时还能使用新的 yield 关键字。

生成器(Generator)是一种特殊的函数,它能够生成一个可迭代对象。生成器函数使用function*关键字定义,并使用yield语句产生值。每次调用生成器函数时,它会返回一个迭代器对象,通过该对象可以逐步获取生成器函数产生的值。

一个简单的例子:

// 生成器
function *createIterator() {
    yield 1;
    yield 2;
    yield 3;
}

// 调用生成器类似于调用函数,但是前者只返回一个迭代器,不执行函数内代码
let iterator = createIterator();

console.log(iterator.next().value);     // 1
console.log(iterator.next().value);     // 2
console.log(iterator.next().value);     // 3

迭代器(遍历器)

在JavaScript中,迭代器(Iterator)是一个带有next()方法的对象。通过在对象上实现next()方法,可以实现对集合中的每个元素进行迭代。next()方法返回一个包含两个属性的对象:value表示当前迭代的值,done表示迭代是否已经结束。

一个简单的例子:

// 遍历器生成函数
function createIterator(items) {
  var i = 0;
  return {
    next: function() {
      var done = (i >= items.length);
      var value = !done ? items[i++] : undefined;

      return {
        done: done,
        value: value
      };
    }
  };
}

var iterator = createIterator([1, 2, 3]);

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 }"

// for all further calls
console.log(iterator.next());           // "{ value: undefined, done: true }"

执行过程

function *foo(){
  console.log('start')
  yield 1
  yield 2
}

const iter = foo()

iter.next()
// ---> start
// ---> {value: 1, done: false}
iter.next()
// --->  {value: 1, done: false}
iter.next()
// --->  {value: undefined, done: true}
  • 1 调用生成器函数会返回一个迭代器(此时生成器内函数不会执行),这是他和普通函数的区别。
  • 2 调用迭代器的next方法会执行生成器函数里面的代码,直到遇到 yield 停止,并跳出函数,返回一个含有yield后面值的对象({ value: undefined, done: true }),程序回到next执行位置。
  • 3 继续调用迭代器的next方法会重复第二步,直到生成器里面的代码全部执行完毕,返回 { value: undefined, done: true }

Symbol.iterator

Symbol.iterator 属性对应一个函数,执行后返回当前对象的遍历器对象。每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。(MDN

1. 原生迭代器

原生支持迭代器的数据结构:Array、Map、Set、String、TypedArray、函数的arguments对象、NodeList对象。

let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();

iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }

上面例子中通过 arr[Symbol.iterator] 取到的就是原生数组的迭代器函数,执行后返回当前数组的遍历器对象 iter。调用该对象的 next 方法,在返回一个值的同时,自动将内部指针移到下一个实例。

2. 自定义迭代器

var myIterable = {}
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};
[...myIterable] // [1, 2, 3]

不符合标准的迭代器

如果一个迭代器 @@iterator 没有返回一个迭代器对象( 带有next 方法的对象),那么它就是一个不符合标准的迭代器,这样的迭代器将会在运行期抛出异常,甚至非常诡异的 Bug。

var nonWellFormedIterable = {}
nonWellFormedIterable[Symbol.iterator] = () => 1
[...nonWellFormedIterable] // TypeError: [] is not a function

应用场景

  1. 遍历集合:通过使用迭代器和生成器,我们可以方便地遍历数组、Map、Set等数据结构中的每个元素,进行相应的操作和处理。
  2. 异步编程:生成器函数可以与Promise对象结合使用,实现更优雅的异步编程方式。通过使用yield语句暂停生成器函数的执行,可以在异步任务完成后恢复并继续执行下一步操作。
  3. 无限序列:有些序列可能是无限的,比如斐波那契数列。通过生成器函数,可以按需生成无限序列中的每个元素,而不必担心内存溢出或计算时间过长的问题。

总结

迭代器和生成器是JavaScript中强大的工具,它们为我们提供了一种便捷和高效的方式来处理和遍历数据集合。通过灵活运用迭代器和生成器,我们能够更好地组织和处理数据,使得代码更加简洁和可读。

参考

转载自:https://juejin.cn/post/7282962960212066365
评论
请登录