iterator
迭代器,它是用于访问集合类的标准访问方法,它可以把访问逻辑从不同类型集合中抽象出来,从而避免向外部暴露集合内部的结构。
比如我们访问一个数组可能使用for循环或者map,foreach,filter等for(int i=0; i<array.size(); i++) { ... get(i) ... }
, 但是当我们想要遍历链表(linkedlist)的时候就得使用while循环while((e=e.next())!=null) { ... e.data() ... }
。
以上两种方式我们都必须知道集合的内部结构是怎么样的我们才可以使用对应的循环方式去循环整个集合,那么这样就造成了很大的耦合度,当我们把一个集合的类型从Arrarlist变成Linkedlist的时候,那么原来客户端的代码必须重写,因为我们集合变了,遍历的方式也必须改成对应的方式。
为解决以上问题,Iterator模式总是用同一种逻辑来遍历集合:for(Iterator it = c.iterater(); it.hasNext(); ) { ... }
,这样就在一定程度上解决了以上的问题。
遍历的方法
遍历数组的方法有很多,这里就不在赘叙了。这里我们就来看一下JS提供给我们用来遍历对象的方法:for…in
Array.prototype.sayHello = function() {
console.log("Hello")
}
Array.prototype.str = 'world';
var arr = ['a', 'b', 'c'];
arr.name = '数组';
for (const key in arr) {
console.log(key);
console.log(typeof key);
console.log(arr[key]);
}
// 输出的是:
// 0 string a
// 1 string b
// 2 string c
// name string 数组
// sayHello string [Function]
// str string world
那么除了for…in之外,还有什么其他方法呢?答案就是现在我们要说的for…of啦!
首先,我们先来了解下for…of的写法,我们这里用for…of遍历上面的数组,看看是什么结果
for (const value of arr) {
console.log(value);
}
// 输出:a,b,c
for…of是 ES6 为了弥补for…in的不足而补充的,目前能够实现遍历的对象有array
,string
,argument
以及后面更高级的set
,Map
详细的看我上一篇 for,for in , for of 和forEach四者对比
是的,for…of暂时还没有实现对object的遍历,但是我们可以通过Symbol.iterator给对象添加这个塑性,我们就可以使用for-of了,代码如下:
var person={
name:'henry',
age:26,
sex:'male'
}
Object.defineProperty(person,Symbol.iterator,{
enumberable:false,
configurable:false,
writable:false,
value:function(){
var _this=this;
var nowIndex=-1;
var key=Object.keys(_this);
return {
next:function(){
nowIndex++;
return {
value:_this[key[nowIndex]],
done:(nowIndex+1>key.length)
}
}
}
}
})
}
//这样的话就可以直接通过for...of来遍历对象了
for(var value of person){
console.log(value )
}
//输出的是:henry,26,male
其实for-of的原理最终也是通过调用person[Symbol.iterator]()
这个函数,这个迭代器函数返回一个next函数,for循环会不断调用next。那么知道原理之后,我们可以自己来模拟一下for…of的内部逻辑
//数组对象
var array = {}
array[Symbol.iterator] = function() {
let index = 1;
return {
next() {
return {done: index>100, value: index++}
}
}
}
//for...of内部,外部传进一个value和一个array
var iterator = array[Symbol.iterator]();
var generator=iterator.next();
while(!generator.done) {
value = generator.value;
console.log(generator.value);
generator=iterator.next();
}
上面使用 iterator.next 和 while 结合实现了 for…of循环。 除了使用iterator 之外,我们还可以使用 yield 语法来实现循环,yield相对简单一些,只要通过 yield 语句把值返回即可:
let array = {
[Symbol.iterator]: function*() {
for(var i=0;i<=100;i++) {
yield i;
}
}
}
for(var value of array ) {
console.log(value);
}
//这个yield其实最后返回的就是iterator函数