javascript中的生成器和迭代器是什么

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 Tair(兼容Redis),内存型 2GB
简介: JavaScript中的生成器和迭代器是处理集合数据的利器,它们提供了一种遍历和操作元素的统一方式。迭代器是具有`next()`方法的对象,返回包含`value`和`done`属性的对象,用于循环处理集合。生成器函数更进一步,可以在执行过程中暂停并返回值,通过`yield`产生迭代值,适用于生成序列、异步编程和实现状态机等场景。例如,一个生成器可以无限生成斐波那契数列,或者在读取文件时控制异步流程。使用这些工具,代码变得更简洁、高效。

生成器函数和迭代器是 JavaScript 中非常有用的工具,它们能够帮助我们轻松地遍历集合数据类型,使代码更加简洁、清晰。他们都是用于处理集合数据类型的工具,它们可以帮助我们迭代集合中的元素,并执行相应的操作。

迭代器

JavaScript中的迭代器是一个对象,它提供了一个统一的接口来遍历集合中的元素,而不需要了解集合的内部实现。通过使用迭代器,我们可以对集合中的元素进行循环处理,每次处理一个元素,直到处理完整个集合为止。

具体来说,一个迭代器对象需要实现一个next()方法,该方法返回一个对象,包含两个属性:valuedonevalue属性包含当前迭代的元素的值,而done属性则是一个布尔值,表示是否已经迭代完整个集合。当迭代完整个集合时,done属性为true,否则为false

JavaScript中的数组、Map、Set等集合数据类型都实现了迭代器接口,可以通过调用其内置的Symbol.iterator方法获取迭代器对象。 下面是一个使用迭代器遍历数组的例子:

javascript

复制代码

const arr = [1, 2, 3, 4, 5];
const iterator = arr[Symbol.iterator]();
let result = iterator.next();
while (!result.done) {
  console.log(result.value);
  result = iterator.next();
}
// 输出1 2 3 4 5

生成器

生成器是一种特殊的函数,它可以在执行过程中暂停,并返回一个迭代器对象。生成器函数通过function*语法来定义,在函数体内使用yield语句可以暂停函数执行,并将值返回给调用方。调用方可以通过迭代器对象来恢复生成器函数的执行,并在下一个yield语句处继续执行。

生成器函数返回的迭代器对象和普通迭代器对象类似,都有一个next()方法,可以用来获取生成器函数中使用yield语句返回的值。但是,生成器函数可以在执行过程中多次返回值,并且可以在每次返回值之间执行一些逻辑操作,这使得生成器函数比普通迭代器更加灵活。

下面是一个使用生成器函数生成斐波那契数列的例子:

javascript

复制代码

function* fibonacci() {
  let [prev, curr] = [0, 1];
  while (true) {
    [prev, curr] = [curr, prev + curr];
    yield curr;
  }
}

const fib = fibonacci();
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
console.log(fib.next().value); // 3
console.log(fib.next().value); // 5
console.log(fib.next().value); // 8

在上面的例子中,fibonacci函数是一个生成器函数,它会生成一个斐波那契数列。在函数体内部,使用了while(true)循环来生成数列中的每一项。在每次循环中,更新prevcurr变量的值,然后使用yield语句返回当前项的值。这个函数可以无限地生成数列,因为它没有终止条件。

在调用fibonacci函数之后,将返回一个迭代器对象fib。我们可以使用next()方法来逐一获取数列中的每一项,并将其打印出来。

在第一次调用fib.next().value时,会执行fibonacci函数中的代码,生成数列中的第一项(值为1),然后暂停函数的执行,并将该值返回给调用方。在第二次调用fib.next().value时,会继续执行fibonacci函数中的代码,生成数列中的第二项(值为2),然后再次暂停函数的执行,并将该值返回给调用方。以此类推,每次调用next()方法,都会从上一次暂停的位置继续执行生成器函数,并生成下一项的值。

我们再来看几个例子。

  1. 处理数据集合

使用迭代器可以方便地遍历数据集合,而生成器可以生成一个可迭代的对象,从而更加方便地处理数据集合。例如,我们可以使用生成器来生成一个无限序列:

ini

复制代码

javascriptCopy code
function* fibonacci() {
  let a = 0, b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

const fib = fibonacci();
for (let i = 0; i < 10; i++) {
  console.log(fib.next().value);
}

在上面的示例中,我们定义了一个 fibonacci 生成器函数,该函数可以生成一个斐波那契数列。通过使用迭代器,我们可以遍历该数列的前 10 项。

  1. 实现异步编程

在 JavaScript 中,生成器可以用来实现异步编程,从而避免回调地狱。通过使用 yield 关键字,我们可以将异步操作挂起,等待异步操作完成后再继续执行。

例如,我们可以使用生成器函数来实现异步读取文件的操作:

javascript

复制代码

function readFile(filename) {
  return new Promise((resolve, reject) => {
    fs.readFile(filename, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
}

function* readFiles() {
  const file1 = yield readFile('file1.txt');
  const file2 = yield readFile('file2.txt');
  console.log(file1.toString());
  console.log(file2.toString());
}

const iterator = readFiles();
iterator.next().value.then(data => iterator.next(data).value)
  .then(data => iterator.next(data));

在上面的示例中,我们定义了一个 readFiles 生成器函数,该函数可以异步读取两个文件的内容,并输出到控制台上。通过使用迭代器和 Promise,我们可以方便地控制异步操作的执行顺序。

  1. 使用迭代器和生成器实现分帧加载大量的 DOM 节点,从而提高页面的性能和响应速度。下面是一个实现分帧加载的示例代码:

javascript

复制代码

function* generateNodes(num) {
  for (let i = 0; i < num; i++) {
    yield createNode(i);
  }
}

function createNode(i) {
  const node = document.createElement('div');
  node.textContent = `Node ${i}`;
  return node;
}

function appendNodes(container, num, interval = 16) {
  const iterator = generateNodes(num);
  let count = 0;
  const handle = setInterval(() => {
    const { value, done } = iterator.next();
    if (done) {
      clearInterval(handle);
      return;
    }
    container.appendChild(value);
    count++;
    if (count === num) {
      clearInterval(handle);
    }
  }, interval);
}

const container = document.getElementById('container');
appendNodes(container, 100000);

在上面的代码中,我们首先定义了一个生成器函数 generateNodes,它接受一个数字参数 num,用于生成指定数量的 DOM 节点。在生成器函数中,我们通过 for 循环来生成每个节点,并使用 yield 关键字将节点返回。

接下来,我们定义了一个辅助函数 createNode,用于创建单个 DOM 节点。在这个函数中,我们使用 document.createElement 方法创建一个新的 div 元素,并将节点的文本内容设置为 Node ${i},其中 i 是节点的索引。

最后,我们定义了一个函数 appendNodes,它接受三个参数:container 表示要将节点添加到的容器元素,num 表示要生成的节点数量,interval 表示分帧加载的时间间隔,默认为 16ms。在函数中,我们首先调用 generateNodes 函数创建一个迭代器,然后使用 setInterval 方法来定时添加节点。在每次定时器回调函数中,我们通过迭代器的 next 方法获取下一个节点,并将节点添加到容器中。当添加完指定数量的节点后,我们清除定时器,并结束函数的执行。

通过以上代码,我们可以将大量的 DOM 节点分帧加载到页面中,避免页面卡顿和响应缓慢的问题。同时,由于采用了迭代器和生成器的方式,代码也更加简洁和易于维护。

总之,生成器和迭代器是 JavaScript 中非常有用的概念,它们可以帮助我们更加方便地处理数据集合、实现异步编程等场景。

  1. generator实现状态机,在 JavaScript 中,可以使用生成器实现状态机,这样可以简化状态机的实现和维护。下面是一个使用生成器实现状态机的示例代码:

javascript

复制代码

function* stateMachine() {
  let state = 'INITIAL';
  while (true) {
    const input = yield state;
    switch (state) {
      case 'INITIAL':
        if (input === 'start') {
          state = 'RUNNING';
        }
        break;
      case 'RUNNING':
        if (input === 'pause') {
          state = 'PAUSED';
        } else if (input === 'stop') {
          state = 'STOPPED';
        }
        break;
      case 'PAUSED':
        if (input === 'resume') {
          state = 'RUNNING';
        } else if (input === 'stop') {
          state = 'STOPPED';
        }
        break;
      case 'STOPPED':
        return;
    }
  }
}

const machine = stateMachine();

console.log(machine.next().value); // INITIAL
console.log(machine.next('start').value); // RUNNING
console.log(machine.next('pause').value); // PAUSED
console.log(machine.next('resume').value); // RUNNING
console.log(machine.next('stop').value); // STOPPED

在上面的代码中,我们定义了一个生成器函数 stateMachine,它表示一个状态机。在状态机中,我们定义了一个状态变量 state,并使用 while 循环和 yield 关键字来构建状态机的迭代器。

在每次迭代中,我们首先使用 yield 关键字将当前状态返回,然后通过 yield 关键字接收输入值 input。根据当前状态和输入值,我们使用 switch 语句来判断状态机的转移逻辑,并更新状态变量 state

最后,我们通过调用 next 方法来启动状态机的迭代器,并逐步输入指定的输入值。在每次迭代中,我们可以通过迭代器的 value 属性获取当前状态,并根据当前状态来决定下一步的操作。

通过以上代码,我们可以使用生成器实现一个简单的状态机,并通过输入不同的指令来控制状态机的运行。使用生成器实现状态机的好处是,可以将状态机的代码结构化和简化,易于维护和修改。

  1. javascript迭代器生成器实现职责链,从而实现请求的分发和处理。下面是一个使用迭代器和生成器实现职责链的示例代码:

javascript

复制代码

function* handler1(next) {
  console.log('Handler 1');
  yield next();
  console.log('Handler 1 after');
}

function* handler2(next) {
  console.log('Handler 2');
  yield next();
  console.log('Handler 2 after');
}

function* handler3(next) {
  console.log('Handler 3');
  yield next();
  console.log('Handler 3 after');
}

function* finalHandler() {
  console.log('Final handler');
}

function runChain() {
  const chain = [handler1, handler2, handler3, finalHandler];
  const iterator = chain.reduceRight((next, fn) => () => fn(next), () => {});
  iterator();
}

runChain();

在上面的代码中,我们定义了三个处理器函数 handler1handler2handler3,以及一个最终处理器函数 finalHandler。这些处理器函数接收一个参数 next,表示下一个处理器函数,同时使用 yield 关键字暂停当前函数的执行,并将执行权转移给下一个函数。

我们还定义了一个 runChain 函数,它将所有的处理器函数按顺序存储在一个数组 chain 中,并使用 reduceRight 方法将所有的处理器函数组合成一个迭代器。在迭代器中,我们将下一个函数作为参数传递给当前函数,并将当前函数作为下一个函数的参数传递给前一个函数,从而形成一个职责链。

最后,我们调用 iterator 方法来启动职责链,并从第一个处理器函数开始执行。在每个处理器函数中,我们先输出当前处理器的标识符,然后使用 yield next() 转移执行权给下一个处理器函数。在最后一个处理器函数中,我们不再使用 yield 关键字,而是直接执行最终处理的逻辑。

通过以上代码,我们可以使用迭代器和生成器实现职责链模式,并将请求的分发和处理封装在不同的处理器函数中,从而提高代码的可维护性和扩展性。

总之,在 JavaScript 中,生成器和迭代器是两个非常有用的概念,它们可以帮助我们更加方便地处理数据集合、异步编程等场景。

转载来源:https://juejin.cn/post/7203218942285725751

相关文章
|
7月前
|
前端开发 JavaScript 中间件
掌握JavaScript中的迭代器和生成器(下)
掌握JavaScript中的迭代器和生成器(下)
|
7月前
|
存储 JavaScript 前端开发
掌握JavaScript中的迭代器和生成器(上)
掌握JavaScript中的迭代器和生成器
105 0
|
3月前
|
JavaScript 前端开发 Python
JavaScript写个.ts视频文件Url生成器,使用了string.padStart
JavaScript写个.ts视频文件Url生成器,使用了string.padStart
|
3月前
|
JavaScript 索引
|
5月前
|
存储 JavaScript 前端开发
JavaScript编码之路【ES6新特性之 Symbol 、Set 、Map、迭代器、生成器】(二)
JavaScript编码之路【ES6新特性之 Symbol 、Set 、Map、迭代器、生成器】(二)
58 1
|
6月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的计算机网络课程试卷生成器附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的计算机网络课程试卷生成器附带文章和源代码部署视频讲解等
41 2
|
5月前
|
JavaScript 索引
JS的迭代器是啥?精读JS迭代器
JS的迭代器是啥?精读JS迭代器
36 0
|
5月前
|
存储 JavaScript 前端开发
JavaScript编码之路【ES6新特性之 Symbol 、Set 、Map、迭代器、生成器】(一)
JavaScript编码之路【ES6新特性之 Symbol 、Set 、Map、迭代器、生成器】(一)
43 0
|
7月前
|
存储 JavaScript 前端开发
JavaScript中的复杂功能实现:一个动态表单生成器
JavaScript中的复杂功能实现:一个动态表单生成器
|
7月前
|
JavaScript 前端开发
什么是 JavaScript 中的生成器
什么是 JavaScript 中的生成器
35 0