ES6标准入门 学习笔记 (08)—— Iterator篇

66 阅读3分钟

引入

系统学习ES6各种特性,了解背后的原理。

本章记录Iterator迭代器(遍历器)

笔记

1.1 迭代器的含义

迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构,只要部署Iterator接口,就可以完成遍历操作。

其作用有三点:

  1. 为各种数据结构提供一个统一的、简便的访问接口
  2. 使得数据结构的成员能够按某种次序排列
  3. 供ES6中的for of循环使用

Iterator遍历过程如下:

  1. 创建一个指针对象,指向当前数据结构的起始位置。
  2. 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
  3. 再次调用next方法,指向第二个成员
  4. 不断调用next方法,直到它指向数据结构的结束位置。

每次调用next方法都会返回当前指向的成员信息,即{value, done}

其中done表示是否遍历结束(指向了结束位置)

1.2 默认Iterator接口

数据结构只要部署了Iterator接口,就称为可迭代(可遍历)的。

ES6规定,默认的Iterator接口部署在此数据结构的Symbol.iterator值为名称的属性上。

所以只要某个数据结构有该属性,就可以认为是可遍历的。调用该方法就可以得到当前数据结构默认的遍历器生成函数

let t = [6, 4, 2]
let it = t[Symbol.iterator]() //遍历器对象

// 自定义可迭代对象
let obj = {
    [Symbol.iterator](){
        return {
            next(){
                return {
                value:1,
                done:true
                }
            }
        }
    }
}

Map, Array, Set, String, TypedArray等等都原生具备了Iterator接口,可以直接用for of进行遍历。

不过注意Map迭代时返回的是键值对数组,而Set是一个值

Object并没有部署该接口(因为对象的属性是无序的,所以严格上说其部署该接口没有必要)

但是如果一定要遍历的话,可以使用Object.values()等方法生成可迭代对象来使用for of

对于类似数组的对象(存在数值键名length属性),部署Iterator接口可以引用数组的Symbol.iterator接口。

如:NodeList上的接口就是如此实现的

NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]

1.3 调用Iterator接口的场合

  1. 解构赋值
  2. 扩展运算符(...)
  3. yield* (如yield* [1,2,3])
  4. 其他场合: for of, Array.from(), Map(), Set(), Promise.all(), Promise.race()

1.4 Iterator接口与Generator函数

迭代器接口的最简单实现还是使用Generator函数

let obj = {
    *[Symbol.iterator](){
        yield 'hello';
        yield 'world';
    }
}

[...obj] // ['hello', 'world']

1.5 遍历器对象的return(), throw()

遍历器对象除了具有next方法,还可以具有可选的return、throw方法

return方法必须返回一个对象,这是Generator规格决定的。

return方法的使用场景:

for of循环提前退出(因为报错或break、continue),就会调用return方法

也可以调用迭代器对象的return()方法,将迭代器将保持在“完成”状态

throw方法主要用于Gererator函数,此处不展开介绍。