TypeScript - 迭代器和生成器



在 TypeScript 中,迭代器和生成器允许控制对可迭代对象的迭代。这里,可迭代对象是指像数组、元组等可以通过迭代的对象。在代码中使用迭代器和生成器允许我们编写高效且易读的代码。

在这里,我们将讨论如何在 TypeScript 中创建自定义迭代器和生成器。

迭代器

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

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

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

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

示例:使用 values() 方法

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

每当我们调用 next() 方法时,它都会返回包含 'value' 和 'done' 属性的对象。您可以看到数组的所有值。每当我们第六次调用 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
    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

编译后,它将生成以下 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

生成器

生成器函数也类似于迭代器,它一次返回一个值,而不是一次返回所有值。当您调用生成器函数时,它返回生成器对象,该对象可用于一次获取一个值。

当您希望一次获取一个值而不是一次获取所有值并将其存储在内存中时,生成器函数非常有用。

语法

用户可以遵循以下语法在 TypeScript 中创建生成器函数。

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

  • 您可以使用 'yield' 关键字从生成器函数中一次返回一个值。

  • 当您调用生成器函数时,它返回生成器对象。

  • 当您调用 next() 方法时,它返回包含 'value' 和 'done' 属性的对象,与迭代器相同。

示例:基本生成器函数

在下面的代码中,numberGenerator() 函数是一个生成器函数。我们使用了 'yield' 关键字,并依次返回了 10、20 和 30 个值。

之后,我们调用了 numberGenerator() 函数,该函数返回生成器对象。要获取值,我们使用生成器对象的 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 代码。

输出

上述示例代码的输出如下:

10
20
30
true

示例:创建生成器函数来遍历范围

在这里,我们定义了 range() 生成器函数,该函数将范围的起始点和终点作为参数。在函数中,我们遍历范围并使用 'yield' 关键字一次返回一个值。

之后,我们使用 'for' 循环和 range() 函数来遍历从 range() 函数返回的生成器对象。循环打印从 range() 函数返回的每个值。

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

输出

1
2
3
4
5

迭代器和生成器之间的区别

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

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