TypeScript Iterators 和 Generators 怎么用?

文章导读
Previous Quiz Next 在 TypeScript 中,iterators(迭代器)和 generators(生成器)允许我们控制对 iterables(可迭代对象)的迭代。可迭代对象包括数组、元组等,我们可以通过它们进行迭代。在代码中使用 iterators
📋 目录
  1. 迭代器
  2. Generators
  3. 迭代器与生成器的区别
A A

TypeScript - 迭代器和生成器



Previous
Quiz
Next

在 TypeScript 中,iterators(迭代器)和 generators(生成器)允许我们控制对 iterables(可迭代对象)的迭代。可迭代对象包括数组、元组等,我们可以通过它们进行迭代。在代码中使用 iterators 和 generators 可以让我们编写高效且易读的代码。

在这里,我们将讨论如何在 TypeScript 中创建自定义 iterators 和 generators。

迭代器

迭代器用于遍历可迭代对象。它是一个特殊的函数,返回迭代器对象。迭代器对象包含 next() 方法,该方法返回一个包含以下 2 个属性的对象。

  • value: value 属性包含序列中下一个元素的数值。

  • done: done 属性包含布尔值,表示迭代器是否到达序列末尾。

让我们来看看下面的迭代器示例。

示例:使用 values() 方法

在下面的代码中,我们定义了一个包含字符串的 'fruits' 数组。'fruits.values()' 返回一个迭代器对象,并将其存储在 'iterator' 变量中。

每次调用 next() 方法时,它都会返回一个包含 'value' 和 'done' 属性的对象。你可以看到数组的所有值。每次调用第 6 次 next() 方法时,由于迭代器已到达序列末尾,它返回的对象的 'value' 属性值为 undefined。

// Defining a fruits array
const fruits = ['apple', 'banana', 'mango', 'orange', 'strawberry'];
// Defining an iterator
const iterator = fruits.values();

// Getting the first element
console.log(iterator.next().value); // apple
// Getting the second element
console.log(iterator.next().value); // banana
// Getting remaining elements
console.log(iterator.next().value); // mango
console.log(iterator.next().value); // orange
console.log(iterator.next().value); // strawberry
console.log(iterator.next().value); // undefined

编译后,将生成以下 JavaScript 代码。

// Defining a fruits array
const fruits = ['apple', 'banana', 'mango', 'orange', 'strawberry'];
// Defining an iterator
const iterator = fruits.values();

// Getting the first element
console.log(iterator.next().value); // apple
// Getting the second element
console.log(iterator.next().value); // banana
// Getting remaining elements
console.log(iterator.next().value); // mango
console.log(iterator.next().value); // orange
console.log(iterator.next().value); // strawberry
console.log(iterator.next().value); // undefined

输出

上述示例代码的输出如下

apple
banana
mango
orange
strawberry
undefined

示例:创建自定义迭代器函数

在下面的代码中,createArrayIterator() 函数是一个自定义迭代器函数。

我们首先定义 'currentIndex' 变量来跟踪可迭代对象中元素的索引。

然后,从函数返回一个包含 'next' 属性的对象。'next' 属性包含一个方法作为值,该方法返回一个包含 'value' 和 'done' 属性的对象。'value' 和 'done' 属性的赋值基于序列中的当前元素。

之后,我们使用 createArrayIterator() 函数遍历数字数组。

// Custom iterator function
function createArrayIterator(array: number[]) {
    // Start at the beginning of the array
    // 从数组开头开始
    let currentIndex = 0;

    // Return an object with a next method
    // 返回一个包含 next 方法的对象
    return {
        // next method returns an object with a value and done property
        // next 方法返回一个包含 value 和 done 属性的对象
        next: function () {
            // Return the current element and increment the index
            // 返回当前元素并递增索引
            return currentIndex < array.length ?
                { value: array[currentIndex++], done: false } :
                { value: null, done: true };
        }
    };
}

// Create an iterator for an array of numbers
const numbers = [10, 20, 30];
const iterator = createArrayIterator(numbers);

console.log(iterator.next().value); // 10
console.log(iterator.next().value); // 20
console.log(iterator.next().value); // 30
console.log(iterator.next().done);  // true

编译后,将生成以下 JavaScript 代码。

// Custom iterator function
function createArrayIterator(array) {
    // Start at the beginning of the array
    let currentIndex = 0;
    // Return an object with a next method
    return {
        // next method returns an object with a value and done property
        next: function () {
            // Return the current element and increment the index
            return currentIndex < array.length ?
                { value: array[currentIndex++], done: false } :
                { value: null, done: true };
        }
    };
}
// Create an iterator for an array of numbers
const numbers = [10, 20, 30];
const iterator = createArrayIterator(numbers);
console.log(iterator.next().value); // 10
console.log(iterator.next().value); // 20
console.log(iterator.next().value); // 30
console.log(iterator.next().done); // true

输出

上述示例代码的输出如下

10
20
30
true

Generators

Generator functions 也类似于 iterators,它们逐个返回值,而不是一次性返回所有值。当你调用 generator function 时,它会返回一个 generator object,可以用来逐个获取值。

Generator functions 主要在你希望逐个获取值而不是一次性获取所有值并将其存储在内存中时非常有用。

Syntax

用户可以遵循下面的语法在 TypeScript 中创建 generator function。

function* func_name() {
    yield val;
  }
const gen = numberGenerator(); // "Generator { }"
console.log(gen.next().value); // {value: val, done: false}
  • 在上面的语法中,我们使用了 'function*' 来定义 generator function。

  • 你可以使用 'yield' 关键字从 generator function 中逐个返回值。

  • 当你调用 generator function 时,它会返回 generator object。

  • 当你调用 next() 方法时,它会返回一个包含 'value' 和 'done' 属性的对象,与 iterator 相同。

Example: Basic Generator Function

在下面的代码中,numberGenerator() function 是一个 generator function。我们使用了 'yield' 关键字,逐个返回 10、20 和 30 的值。

之后,我们调用了 numberGenerator() function,它返回 generator object。为了获取值,我们使用 generator object 的 next() 方法。

// Basic generator function
function* numberGenerator() {
    yield 10;
    yield 20;
    yield 30;
}

// Create a generator object
const gen = numberGenerator();

// Call the generator function
console.log(gen.next().value); // 10
console.log(gen.next().value); // 20
console.log(gen.next().value); // 30
console.log(gen.next().done);  // true

编译后,它会生成相同的 JavaScript 代码。

Output

上述示例代码的输出如下

10
20
30
true

Example: Creating the Generator Function to Traverse a Range

在这里,我们定义了 range() generator function,它将范围的起始点和结束点作为参数。在函数中,我们遍历范围并使用 'yield' 关键字逐个返回值。

之后,我们使用 'for loop' 和 range() function 来遍历从 range() function 返回的 generator object。循环会打印从 range() function 返回的每个值。

// Generators are functions that allow to traverse a range
function* range(start: number, end: number) {
    // Loop through the range
    for (let i = start; i <= end; i++) {
        // Yield the current value
        yield i;
    }
}

// Loop through the range
for (const num of range(1, 5)) {
    console.log(num); // 1, 2, 3, 4, 5
}

编译后,它会生成以下 JavaScript 代码。

// Generators are functions that allow to traverse a range
function* range(start, end) {
    // Loop through the range
    for (let i = start; i <= end; i++) {
        // Yield the current value
        yield i;
    }
}

// Loop through the range
for (const num of range(1, 5)) {
    console.log(num); // 1, 2, 3, 4, 5
}

Output

1
2
3
4
5

迭代器与生成器的区别

迭代器和生成器看起来相似。然而,它们是不同的。这里,我们解释了两者之间的一些区别。

特性 Iterator Generator
定义 一个遵循 Iterator 协议的对象,具体实现了 next() 方法。 一个可以暂停执行并恢复的 function,它会自动在内部管理状态。
控制机制 通过 next() 方法手动控制迭代,该方法返回 { value, done } 使用 yield 来暂停并返回值,使用 next() 来恢复。
语法 通常涉及创建一个带有 next() 方法的对象。 使用 function* 语法定义,并包含一个或多个 yield 语句。
使用复杂度 较高,因为需要显式状态管理和自定义 next() 实现。 较低,因为 yield 简化了状态管理和迭代控制。
理想使用场景 适用于需要显式控制的简单自定义迭代。 更适合复杂序列、异步任务,或利用惰性执行的情况。