迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而不须要暴露该对象的内部表示。数据结构
迭代器分为内部迭代器和外部迭代器。内部迭代器只需一次初始调用,而外部迭代器必须显式地请求迭代下一个元素,这样咱们就能够手动控制迭代过程。异步
实现一个内部迭代器:函数
Array.prototype.innerIterator = function(callback){ for (let i = 0, len = this.length; i < len; i++) { callback && callback.call(this[i], this[i], i) } }; [1,2,3].innerIterator(function(item, index){ console.log('item:', item, 'index:', index) }) // item: 1 index: 0 // item: 2 index: 1 // item: 3 index: 2
实现一个外部迭代器:this
Array.prototype.outerInterator = function(){ let index = 0; return { next: () => { return index < this.length ? {value: this[index++], done: false}: {value: undefined, done: true} } } } let iterator = [1,2,3].outerInterator(); for(let next; (next = iterator.next()) && !next.done;) { console.log('item', next.value) } // item 1 // item 2 // item 3
了解了迭代器模式,再来看看 ES6 中补充的迭代协议。可迭代(iterable)协议和迭代器(iterator)协议。prototype
可迭代协议:
一个可迭代对象(或其原型上),必须有一个 Symbol.iterator
的属性,该属性所对应的值为返回一个对象的无參函数,被返回对象符合迭代器协议。当可迭代对象须要迭代时,调用该方法。code
一些数据类型内置了 @@iterator
方法,有本身默认的迭代行为。(String, Array, TypedArray, Map , Set 等都是内置可迭代对象, 由于它们的原型对象都有一个 @@iterator
方法.)([Symbol.iterator]
、@@iterator
能够认为是一回事)对象
let iterator = ('hi')[Symbol.iterator]() var a = iterator.next(); // a { value: 'h', done: false }
迭代器协议:
一个迭代器必须实现了 next()
方法,该方法是返回一个对象的无參函数。被返回的对象有两个必要的属性:done 和 value。ip
Array.prototype.Iteration = function(){ let index = 0; return { [Symbol.iterator](){return this}, next: () => { return index < this.length ? {value: this[index++], done: false}: {value: undefined, done: true} } } }; let Iteration = [2, 3, 4].Iteration(); for(let value of Iteration) { console.log('value', value) } // value 2 // value 3 // value 4
不能发现,Iteration 同时知足可迭代协议和迭代协议。又由于是可迭代的,for...of
是能够直接使用,并且这个和外部迭代器十分类似。原型
一旦一种数据结构有了 @@iterator
方法后, 就认为是可迭代的。ES6 中许多新的方法就是基于此的 解构赋值
、扩展运算符
、yield*
,还有 for..of
、Array.from()
等。it
知道了以上知识,也就知道了为何对象不能够直接使用 for...of
了。不过咱们能够在对象原型上添加 @@iterator
方法,使之成为可迭代的。
Object.prototype.Iteration = function(){ let keys = Object.keys(this), index = 0; return{ [Symbol.iterator](){return this}, next: () => { let current = index++; return current < keys.length? {value: [keys[current], this[keys[current]]], done: false}: {value: undefined, done: true}; } } } let iterator = {'a': 1, 'b': 2, 'c': 3}.Iteration(); for(let [key, value] of iterator) { console.log('key:', key, 'value:', value) } // key: a value: 1 // key: b value: 2 // key: c value: 3
像以上的的对象都是咱们本身手动实现的,符合可迭代协议和迭代协议的对象。看起来很麻烦,还好这些工做已经有函数替咱们作了,那就是生成器函数。
生成器函数是能够做为迭代器工厂的函数,当它被执行时会返回一个新的 Generator 对象,该对象符合可迭代协议和迭代器协议。
如今咱们用生成器函数使得对象符合迭代协议:
Object.prototype.Iteration = function *(){ for(let [key, value] of Object.entries(this)){ yield [key, value] } } for(let [key, value] of {'a': 1, 'b': 2, 'c': 3}.Iteration()) { console.log('key:', key, 'value:', value) } // key: a value: 1 // key: b value: 2 // key: c value: 3
在这里生成器只是做为迭代器而已,其实它仍是消息双向传递系统。也正是这些特性的存在,使得异步流程控制又向前迈了一大步。