迭代器形式
迭代器形式是指供应一种要领递次接见一个聚合对象中的各个元素,而不须要暴露该对象的内部示意。
迭代器分为内部迭代器和外部迭代器。内部迭代器只需一次初始挪用,而外部迭代器必需显式地要求迭代下一个元素,如许我们就能够手动掌握迭代历程。
完成一个内部迭代器:
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
完成一个外部迭代器:
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)协定。
可迭代协定:
一个可迭代对象(或其原型上),必需有一个 Symbol.iterator
的属性,该属性所对应的值为返回一个对象的无参函数,被返回对象相符迭代器协定。当可迭代对象须要迭代时,挪用该要领。
一些数据类型内置了 @@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。
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()
等。
知道了以上学问,也就知道了为何对象不能够直接运用 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
在这里生成器只是作为迭代器罢了,实在它照样音讯双向通报体系。也恰是这些特征的存在,使得异步流程掌握又向前迈了一大步。