ES6+ 迭代协议
1. 前言
上一节我们对 ES6 新增的 for...of 做了深入的讲解,它可以用于字符串、数组、类数组、以及新增的数据结构 Map/Set 等进行遍历。但是这些能够使用 for...of 进行遍历的都有 一个 共同的特性 —— 可迭代。那什么是可迭代呢?
ECMAScript 2015 在一组补充规范中规定了两个协议:可迭代协议和迭代器协议。这两个规定不是新的内置实现或语法,而是 协议 。这些协议可以被任何数据结构遵循,从而可以实现 自定义 的遍历,而这些遵守迭代协议的数据结构是可以被 for...of 遍历的。有了这样的 一个 规范,我们所定义的数据结构就会更加丰富了,本节我们将深入 ES6 中的迭代。
2. 可迭代协议和迭代器协议
迭代协议 包括 两方面的 内容 —— 可迭代协议和迭代器协议,下面我们就来看看这两个协议都是什么。
2.1 可迭代协议
什么是可迭代协议?可以通过 JavaScript 对象定义或定制迭代行为,在 JavaScript 中有一些内置类型并且满足内置的可迭代对象,具有迭代的行为。如 Array、Map、Set 等。还有 一个 比如字面量对象(Object)则没有,如果要对 Object 进行迭代的话需要使用 for...in 循环,但是 for...in 在循环时需要判断是否是自身 属性 。所以很多时候如果想用 for...of 进行迭代时就需要使用对象上的 Object.keys() 等 方法 提取 对象中的 keys 后再去进行遍历操作。
在 ES6 中可迭代协议规定想要成为可迭代对象,这个对象必须实现 @@i tera tor 方法 。这意味着对象(或者它原型链上的某个对象)必须有 一个 键为 @@i tera tor 的 属性 ,可通过常量 Symbol.i tera tor 访问该 属性 。所以, 一个 对象满足可迭代协议的关键在于实现 Symbol.i tera tor 方法 ,这个 方法 的返回值是 一个 符合迭代器协议的对象,并且是 一个 无参数的 函数 。
2.2 迭代器协议
上面说到了在实现 Symbol.i tera tor 方法 时需要返回 一个 满足迭代器协议的 方法 。那么迭代器协议又是什么呢?
迭代器协议定义了产生一系列值的 一个 标准方式,迭起协议规定需要返回 一个 带 next() 方法 的对象。 next() 可以被多次执行,每次执行都会返回 一个 对象,该对象包含两个 属性 , done 和 value :
done 是 一个 boolean,在没有迭代完时返回 false,迭代完成后返回 true; value 就是被迭代的返回值,当 done 为 true 时可以省略。
实现了以上两点才会满足 一个 迭代器协议。一般来说可迭代协议和迭代器协议在实际的场景中是 同时存在 的。下面我来看看什么是迭代器?并且怎么使用可迭代协议和迭代协议去实现 一个 迭代器。
3. 迭代器
这里说的迭代器是遵循上面两个协议来实现的,在满足两个协议时,我们可以显式地通过不断 调用 next () 方法 去进行迭代。在迭代 一个 迭代器后,我们称之为消耗了这个迭代器而,且每个迭代器只能执行一次。下面我们来看看怎么实现 一个 迭代器:
var obj = { } obj [ Symbol . i tera tor ] = function ( ) { let index = ; return { next ( ) { if ( index <= ) { return { value : index ++ , done : false } } else { return { done : true } } } } }
上面的 代码 中根据可迭代协议给 obj 对象 添加 一个 Symbol.i tera tor 方法 ,再根据迭代器协议返回 一个 next() 方法 ,在每次消耗 next() 时对 index 进行加 1 操作。当 index 大于 10 的时候结束迭代行为,之后再消耗 next() 返回值不变。
根据上面的 代码 ,我们可以显式的手动 调用 next() :
var i tera tor = obj [ Symbol . i tera tor ] ( ) ; var s = i tera tor . next ( ) ; while ( ! s . done ) { console . log ( s . value ) ; s = i tera tor . next ( ) ; } // 1 // 2 // ...
执行上面的 代码 ,在浏览器的控制台中,可以看到大于的结果是 1 到 10。上面是我们手动执行消耗 next() 的方式,上面我们也说了,只要满足迭代协议就可以被 for...of 循环,那是不是真的是这样的呢?下面我们就使用 for...of 对 obj 进行循环。
for ( let i of obj ) { console . log ( i ) } // 1 // 2 // ...
在控制台中执行上面的 代码 ,可以看到和我们使用手动 调用 next() 方式返回打印的结果是一样的。
4. 小结
本节我们主要学习了两个协议 —— 可迭代协议和迭代器协议,并且通过这两个协议实现了 一个 迭代器。通过这个迭代器我们知道,在满足这两个协议后就可以使用 for...of 进行循环,并且我们进行 显示 调用 进行了验证。
插入案例