迭代器(Iterator)
在迭代器模式中,你有一个对象包含了一些集合数据(aggregate data)。这些数据在内部可能存在一个非常复杂的数据结构中,但你想提供简单的方法去访问结构中的每个元素。
你的代码使用者就不需要去了解你是如何组织你的数据;他们需要就是使用单独的元素。
在迭代器模式中,你的对象需要提供一个next()方法。顺序调用next()将会返回下一个连续的元素,“下一个”在你的数据结构中的意义取决于你的决定。
假设你的对象叫做egg,你可以简单的通过在一个循环中调用next()访问每一个数据元素,就像这样:
var element;
while (element = agg.next()) {
// do something with the element ...
console.log(element);
}
在迭代器模式中,集合对象通常也提供一个方便的hasNext()方法,那么对象的使用者就可以他们是否到达你的数据的尾部。另一种顺序访问所有元素的方法,这次我们使用hasNext(),可能就像下面这样:
while (agg.hasNext()) {
// do something with the next element...
console.log(agg.next());
}
现在我们有了用例,让我们看一下如何去实现这样一个集合对象。
当实现迭代器模式时,私下里储存数据和一个指向下一个有效元素的指针(下标)是有意义的。为了展示一个简单的实现, 我们假设数据仅是一个普通的数组,检索下一个连续元素的“特殊(special)”逻辑是返回隔一个元素的数组元素。
var agg = (function() {
var index = 0,
data = [1, 2, 3, 4, 5],
length = data.length;
return {
next: function() {
var element;
if (!this.hasNext()) {
return null;
}
element = data[index];
index = index + 2;
return element;
},
hasNext: function() {
return index < length;
}
};
} ());
为了更简单的访问数据和迭代数据多次的能力,你的对象可能提供额外的方便的方法:
rewind()
重置指针指向起始值
current()
返回当前元素,因为你使用next()实现不了,不让指针前进。
实现这些方法将不会出现任何困难:
var agg = (function() {
// [snip...]
return {
// [snip...]
rewind: function() {
index = 0;
},
current: function() {
return data[index];
}
};
} ());
现在测试迭代器:
// this loop logs 1, then 3, then 5
while (agg.hasNext()) {
console.log(agg.next());
}
// go back
agg.rewind();
console.log(agg.current()); // 1
结果将会在控制台打印:1,3,5(循环打印)且最后1(在rewind之后)。