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 簡化。
理想用例 適用於需要顯式控制的簡單自定義迭代。 更適合複雜序列、非同步任務或利用惰性執行的情況。
廣告