ES6 迭代器:Iterator, Iterable 和 Generator

栏目: JavaScript · 发布时间: 5年前

内容简介:对集合中每个元素进行处理是很常见的操作,比如数组遍历、对象的属性遍历。 以往这些操作是通过本文展开介绍了这些相关概念:Iterables(可迭代对象)、Iterator(迭代器)、 Generator(生成器)和 Generator Function(生成器函数), 以及相关机制:Iterable Protocol、Iterator Protocol、Symbol.iterator。实现了 Iterable Protocol 的对象称为

对集合中每个元素进行处理是很常见的操作,比如数组遍历、对象的属性遍历。 以往这些操作是通过 for 循环、 .forEach.map 等方式进行, 在 ES6 中直接把迭代放在语言层面进行支持,同时提供定制 for...of 的机制。 借由迭代器机制为 Map、Array、String 等对象提供了统一的遍历语法,以及更方便的相互转换。 为方便编写迭代器还提供了生成器(Generator)语法。

本文展开介绍了这些相关概念:Iterables(可迭代对象)、Iterator(迭代器)、 Generator(生成器)和 Generator Function(生成器函数), 以及相关机制:Iterable Protocol、Iterator Protocol、Symbol.iterator。

Iterables 和 Iterators

实现了 Iterable Protocol 的对象称为 可迭代对象(Iterables) ,这种对象可以用 for...of 来遍历。 Map , Set , Array, String 都属于可迭代对象。 自定义的对象也可以使用这一机制,成为可迭代对象。

Iterable Protocol:需要实现一个 ECMA @@iterator 方法,即在键 [Symbol.iterator] 上提供一个方法。对象被 for...of 调用时,这个方法会被调用。方法应该返回一个迭代器对象(Iterator)用来迭代。

实现了 Iterator Protocol 的对象称为 迭代器对象(Iterator) ,也就是我们说的迭代器对象。

Iterator Protocol:又称 Iteration Protocol,需要实现一个 next() 方法,每次调用会返回一个包含 value (当前指向的值)和 done (是否已经迭代完成)的对象。

标准 Iterables 举例:Array

Array 可以用 for...of 来遍历,是一个可迭代对象。 我们来观察它是如何实现上述 Protocol 的。首先拿到它的 Symbol.iterator 属性(Iterable Protocol):

let arr = ['Alice', 'Bob', 'Carol']
let iterator = arr[Symbol.iterator]()

然后调用它的 .next() 方法(Iterator Protocol)得到,直到 done === true

console.log(iterator.next())    // { value: 'Alice', done: false }
console.log(iterator.next())    // { value: 'Bob', done: false }
console.log(iterator.next())    // { value: 'Carol', done: false }
console.log(iterator.next())    // { value: undefined, done: true }

自定义 Iterables

除了 Array、Map 等标准的全局对象外,我们的自定义对象也可以通过提供一个 Symbol.iterator 成为 Iteratable。 比如实现一个 50 以内的 斐波那契数列

let obj = {
    [Symbol.iterator]: function () {
        let a = 0, b = 0
        return {
            next: function () {
                let value = 0
                if (!a) {
                    value = a = 1
                }
                else if (!b) {
                    value = b = 1
                }
                else if (b < 50){
                    value = a + b
                    a = b
                    b = value
                }
                return {done: value === 0, value}
            }
        }
    }
}
for (let i of obj) {
    console.log(i)  // 1 1 2 3 5 8 13 21 34 55
}

利用 Generator

上述迭代器中我们维护了 ab 两个状态,以及每次调用进入的条件分支。 ES6 提供了 Generator Function (生成器方法)来方便上述迭代器的实现。 生成器方法返回的 Generator 对象 直接就是一个实现了 Iterator Protocol 的对象。

下面使用生成器方法重新实现50以内的斐波那契数列:

let obj = {
    [Symbol.iterator]: function *() {
        let a = 1, b = 1
        yield a
        yield b
        while (b < 50) {
            yield b = a + b
            a = b - a
        }
    }
}
for (let i of obj) {
    console.log(i)  // 1 1 2 3 5 8 13 21 34 55
}

Map, Set, String, Array 互相转换

Iteration Protocol 给出了统一的迭代协议,使得不同类型的集合间转换更加方便,也方便了编写适用于不同类型集合的算法。 这一概念类似 Lodash 中的 Collection, 或者STL 中的迭代器。以下是一些很方便的转换技巧:

Array 生成 Set ,可用于数组去重:

new Set(['Alice', 'Bob', 'Carol'])    // {'Alice', 'Bob', 'Carol'}
// 等价于
new Set(['Alice', 'Bob', 'Carol'][Symbol.iterator]())

Set 得到 Array

let set = new Set(['Alice', 'Bob', 'Carol'])
Array.from(set) // 'Alice', 'Bob', 'Carol'
// 等价于
Array.from(set[Symbol.iterator]())

除了 for...of 外, 展开语法 (Spread Syntax) ... 也支持迭代器(Iterables)。借此可以简写作:

let set = new Set(['Alice', 'Bob', 'Carol'])
let names = [...set]        // 'Alice', 'Bob', 'Carol'

StringSet ,得到字符串中包含的字符:

let alphabet = 'abcdefghijklmnopqrstuvwxyz';
new Set(alphabet)           // {'a', 'b', 'c', ...}
// 等价于
new Set('alice bob'[Symbol.iterator]())

ObjectMap ,也就是把传统的 JavaScript 映射转换为 Map

let mapping = {
    "foo": "bar"
}
new Map(Object.entries(mapping))    // {"foo" => "bar"}

类似地, Object 的键的集合可以这样获取:

let mapping = {
    "foo": "bar"
}
new Set(Object.keys(mapping))    // {"foo"}

参考链接

  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
  • https://www.ecma-international.org/ecma-262/6.0/#sec-iteration
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

以上所述就是小编给大家介绍的《ES6 迭代器:Iterator, Iterable 和 Generator》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

解决网页设计一定会遇到的210个问题

解决网页设计一定会遇到的210个问题

2006-4 / 42.00元

如何选择适合、简单、方便、快速的方法来解决您的网页设计问题?不会HTML、JavaScript、CSS也可轻易完成许多网页功能与特效。本书包含上百种HTML、JavaScript、CSS使用应用技巧与盲点解说,包含10个常用表单资料判断函数与特殊技巧,不必修改就可用于任何网页。本书现有的多数网页设计书籍相辅相成,让您事半功倍地完成工作。   许多计算机书籍都是从某个语言或者某个软件的......一起来看看 《解决网页设计一定会遇到的210个问题》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换