2

JavaScript 迭代器教程

 1 year ago
source link: https://www.myfreax.com/javascript-iterator/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
JavaScript 迭代器教程

JavaScript 迭代器教程

在本教程中,您将了解 JavaScript 迭代器以及如何使用迭代器更有效地处理数据序列。

for 循环问题

当你有一个数据数组时,你通常使用 for 循环来迭代它的元素。例如:

let ranks = ['A', 'B', 'C'];

for (let i = 0; i < ranks.length; i++) {
    console.log(ranks[i]);
}

for 循环使用变量  i 来跟踪 ranks 数组的索引。每次循环执行时,只要 i 的值小于 ranks 数组中的元素数,它的 i 值就会递增。

这段代码很简单。但是,当您将一个循环嵌套在另一个循环中时,它的复杂性会增加。此外,跟踪循环内的多个变量很容易出错。

ES6 引入一种新的循环结构称为 for...of ,来消除标准 for 循环的复杂性并避免因跟踪 for 循环索引而导致的错误。

要迭代 ranks 数组的元素,您可以使用以 for...of 循环:

for(let rank of ranks) {
    console.log(rank);
}

for...offor 循环优雅得多,因为它展示代码的真正意图并遍历数组访问每个元素。

最重要的是,for...of 循环能够在任何可迭代对象上创建一个循环,而不仅仅是一个数组。要了解可迭代对象,您需要先了解迭代协议。

有两种迭代协议:iterable protocol iterator protocol

迭代器协议 iterator protocol

当一个对象实现下面两个接口时,它就是一个迭代器:

  • 有没有剩下的元素?
  • 如果有,元素是什么?

从技术上讲,当一个对象有一个 next() 方法返回具有以下两个属性的对象,它就被称为迭代器:

  • done:  布尔值,指示是否还有可以迭代的元素。
  • value: 当前元素。

每次调用 next() 时,它都会返回集合中的下一个值:

{ value: 'next value', done: false }

如果在调用 next() 方法返回最后一个值,则 next() 方法返回结果对象如下:

{done: true: value: undefined}

属性 done 的值表示没有更多的值可返回,属性 value 的设置为 undefined

可迭代协议

当一个对象包含一个称为 [Symbol.iterator] 的方法,该不接受任何参数并返回一个符合迭代器协议的对象时,则该对象是可迭代的。

 [Symbol.iterator] 是 ES6 内置的众所周知的符号之一。

由于 ES6 为集合类型 ArraySetMap 提供内置迭代器 ,因此您不必为这些对象创建迭代器。

如果您有自定义类型并希望使其可迭代可以使用 for...of 循环进行遍历,则需要实现迭代协议。

以下代码创建一个 Sequence 对象,该对象返回指定 start, end 范围内的数字列表,后续数字之间有一个 interval

class Sequence {
    constructor( start = 0, end = Infinity, interval = 1 ) {
        this.start = start;
        this.end = end;
        this.interval = interval;
    }
    [Symbol.iterator]() {
        let counter = 0;
        let nextIndex = this.start;
        return  {
            next: () => {
                if ( nextIndex <= this.end ) {
                    let result = { value: nextIndex,  done: false }
                    nextIndex += this.interval;
                    counter++;
                    return result;
                }
                return { value: counter, done: true };
            }
        }
    }
};

以下代码在 for...of 循环中使用 Sequence 迭代器:

let evenNumbers = new Sequence(2, 10, 2);

for (const num of evenNumbers) {
    console.log(num);
}
2
4
6
8
10

您可以显式访问 [Symbol.iterator]() 方法,如下所示:

let evenNumbers = new Sequence(2, 10, 2);
let iterator = evenNumbers[Symbol.iterator]();

let result = iterator.next();

while( !result.done ) {
    console.log(result.value);
    result = iterator.next();
}

迭代器 return 方法

除了 next() 方法之外,还可以选择  [Symbol.iterator]()  返回一个名为 return() 的方法。

当迭代过早停止时,将自动调用 return() 方法。您可以在其中放置清理资源的代码。

下面的示例实现 Sequence 对象的 return()方法:

class Sequence {
    constructor( start = 0, end = Infinity, interval = 1 ) {
        this.start = start;
        this.end = end;
        this.interval = interval;
    }
    [Symbol.iterator]() {
        let counter = 0;
        let nextIndex = this.start;
        return  {
            next: () => {
                if ( nextIndex <= this.end ) {
                    let result = { value: nextIndex,  done: false }
                    nextIndex += this.interval;
                    counter++;
                    return result;
                }
                return { value: counter, done: true };
            },
            return: () => {
                console.log('cleaning up...');
                return { value: undefined, done: true };
            }
        }
    }
}

以下代码段使用 Sequence 对象生成从 1 到 10 的奇数序列。但是,它过早地停止迭代。最后,return() 方法被自动调用。

let oddNumbers = new Sequence(1, 10, 2);

for (const num of oddNumbers) {
    if( num > 7 ) {
        break;
    }
    console.log(num);
}
1
3
5
7
cleaning up...

在本教程中,您了解了 JavaScript 迭代器以及如何使用迭代协议来实现自定义迭代逻辑。

微信公众号

支付宝打赏

myfreax 淘宝打赏

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK