一、迭代器模式
定义
按一定顺序访问一个集合,使用者无需知道集合的内部结构(封装)。
例子
class Iterator {
constructor(container) {
this.list = container.list
this.index = 0
}
next() {
if(this.hasNext()) {
return this.list[this.index++]
}
return null
}
// 是否还能往下走
hasNext() {
if(this.index == this.list.length) {
return false
}
return true
}
}
class Container {
constructor(list) {
this.list = list
}
// 生成迭代器
getIterator() {
return new Iterator(this)
}
}
let arr = [1,2,3,4,5];
let container = new Container(arr);
let iterator = container.getIterator();
while(iterator.hasNext()) {
console.log(iterator.next()); // 1 2 3 4 5
}
例子
一、ES6中的Iterator
ES6中,有序集合的数据类型有很多(Array Map Set String arguments...),每个都写一个遍历方法就会很繁杂,所以用一个统一的接口来遍历所有的数据类型。
上述数据类型都有Symbol.iterator属性。这个属性是一个函数,执行后返回一个迭代器。for...of...语法就是调用了这个迭代器。
function each(data, cb) {
// 生成遍历期
let iterator = data[Symbol.iterator]()
let item = iterator.next()
while(!item.done) { // done属性用来判断是否到最后一位
cb(item.value); // value是当前遍历到的值
item = iterator.next(); // 指向迭代器的下一位
}
}
let arr = [1,2,3,4,5,6];
let nodeList = document.getElementsByTagName('p');
each(arr,item => {
console.log(item); // 1 2 3 4 5 6
})
each(nodeList,item => {
console.log(item);
})
for(item of arr) {
console.log(item) // 1 2 3 4 5 6
}
for(item of nodeList) {
console.log(item)
}
从上面的例子可以看出来,其实for...of...语法就是我们自定义的each函数的语法糖。
对于对象之类的没有迭代器的数据类型,我们可以自定义迭代器,让数据按我们想要的顺序进行遍历。
let fakeArray = {
_values: [1,2,3,4,5,6],
[Symbol.iterator]() {
let _values = this._values;
let _index = 0;
let done = function() {
return _index >= _values.length;
}
return {
next() {
return done() ? {
value: _values[_index],
done: true,
} : {
value: _values[_index++],
done: false,
}
}
}
}
}
for(item of fakeArray) {
console.log(item) // 1 2 3 4 5 6
}
ES6的iterator就很好的使用了迭代器模式的思想,用for...of...的时候,数据按照一定顺序遍历,但我们不关心他的遍历顺序。
二、Generator
ES6中,iterator也运用到了generator(生成器函数)当中。通过Generator和Promise可以完美解决异步问题。在这里不做过多讲述,感兴趣的小伙伴可以自行查阅资料。
设计原则
迭代器对象和目标对象分离
迭代器将使用者与目标对象隔离开
符合开放封闭原则