迭代器模式
迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代模式可以把迭代的过程从业务逻辑中分离出来,在使用中,即使不关心对象的内部构造,也是可以按顺序访问其中的每个元素的。
迭代器的特点
- 访问一个聚合对象的内容而不需要暴露它的内部表示
- 为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作
许多浏览器也支持JavaScript的Array.prototype.forEach。
forEach的使用示例如下:
var arr = [1,2,3,4,5,6,7];
var arr1 = ['a','b','c','d','e','f'];
arr.forEach(function(value,index,array){
console.log("第"+index+"个元素的值为"+value+"原数组:"+array);
})
arr.forEach(function(value,index,array){
console.log("第"+index+"个元素的值为"+value+"原数组:"+array);
console.log(this);//这个里面的this指向arr1
console.log(this[index]);//访问arr1中下表为index的值
},arr1)
jQuery的迭代器
迭代器无非就是循环访问聚合对象中的各个元素。入jQuery中的$.each函数,其中毁掉函数中的参数i为当前的索引,n为当前元素。
示例:
- 迭代数组
var arr = [1,22,3,4,5,6]
$.each(arr,function(i,value){
console.log('下标:'+i+"值:"+value);
});
- 迭代DOM树
<div id="box">
<ul>
<li>li-1</li>
<li>li-2</li>
<li>li-3</li>
<li>li-4</li>
<li>li-5</li>
</ul>
</div>
$(function(){
var liElem = $("#box li");
$.each(liElem,function(i,item){
console.log(i+":"+$(this).text());
console.log(this)
//给每个li添加一个点击事件
$(this).click(function(){
alert(i+":"+$(this).text())
})
})
//或如下代码
$("#box li").each(function(i,item){
console.log(i+":"+$(this).text());
console.log(this)
})
})
实现自定义的迭代器
模拟一个each函数,each函数接受2个参数,第一个参数为被循环的数组,第二个参数为循环中的每一步后将被触发的回调函数。如下:
var arr1 = ['a','b','c','d']
var each = function(arr,callback){
for(var i = 0; i < arr.length; i++){
callback.call(arr[i],i,arr[i]);
//callback.call(arr1,i,arr[i]);
}
}
each([1,2,3,44],function(index,value){
console.log("第"+index+"个:"+value);
console.log(this);
})
内部迭代器和外部迭代器
迭代器可分为内部迭代器和外部迭代器。
1. 内部迭代器
内部迭代器已经定义好了迭代规则,它完全接手整个迭代过程,外部只需要一次初始调用。如上面的each函数。
内部迭代器在调用的时候非常方便,不需要关心迭代器内部的实现,跟迭代器的交互也仅仅是一次初始调用,但者也是迭代器的缺点。这是由于内部迭代器的迭代规则已经被提前规定。
示例:判断两个数组里的元素的值是否完全相同;不该写each函数本身的代码,则只能修改each函数的回调函数
var each = function(arr,callback){
for(var i = 0; i < arr.length; i++){
callback.call(arr[i],i,arr[i]);
}
}
var compare = function(arr1,arr2){
if(arr1.length !== arr2.length){
throw new Error('两个数组不相等,长度不同');
}
each(arr1,function(index,value){
if(value !== arr2[index]){
throw new Error("两个数组不相等,详见下标为"+index);
}
});
alert('两个数组相等');
}
compare([1,2,3,4],[1,2,3])
compare([1,2,3],[1,2,3,4])
compare([1,2,3],[1,2,3])
compare([1,2,3],[1,2,'3'])
总结
compare这个函数一点点也不好,能完成要求还是因为Javascript可以把函数当作参数传递的特性。
在一些没有闭包的语言中,内部迭代器本身的实现也是相当复杂的。比如:C语言中的内部迭代器使用函数指针来实现的,循环处理所需要的数据都是要以参数的形式明确地从外面传递进去。
2.外部迭代器
外部迭代器必须显示的请求迭代下一个元素
外部迭代器增加了一些调用的复杂度,但相对也增强了迭代器的灵活性。
var Iterator = function(obj){
var current = 0;
var next = function(){
current += 1;
};
var isDone = function(){
return current >= obj.length;
};
var getCurrItem = function(){
return obj[current];
};
var aindex = function(){
return current
}
return {
next: next,
isDone:isDone,
getCurrItem:getCurrItem,
aindex:aindex
}
}
var compare = function(iterator1,iterator2){
//如果有一个没有遍历完那么应该进行继续执行
while(!iterator1.isDone() || !iterator2.isDone()){
//判断长度是否相等
if(iterator1.isDone() && iterator2.isDone()){
throw new Error('not eq of len,index is:'+iterator1.aindex());
}
if(iterator1.getCurrItem() !== iterator2.getCurrItem()){
throw new Error('not eq,index is:'+iterator1.aindex());
}
iterator1.next();
iterator2.next();
}
alert('eq');
}
var iterator1 = Iterator([1,2,'3',4]);
var iterator2 = Iterator([1,2,3]);
console.log(iterator1)
compare(iterator1,iterator2)
总结
外部迭代器虽然调用方式相对复杂,但它的适用面更广,也能满足更多变的需求。内部迭代器和外部迭代器在实际生产中没有优劣之分,
迭代类数组对象和字面量对象
迭代器模式不仅可以迭代数组,还可以迭代一些类数组对象。如:arguments、{“0”:1,“1”:2},无论是类内部迭代器还是外部迭代器,只要被迭代的对象具有length属性而且可以使用下标访问,那么就可以进行迭代。
在Javascript中,for in语句可以用来迭代普通字面量对象属性。jQuery函数通过$.each函数来封装各种迭代行为。