再起航,我的学习笔记之JavaScript设计模式25(迭代器模式)
迭代器模式
概念介绍
迭代器模式(Iterator): 在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的元素。
迭代器
程序中的循环是一种利器,循环语句也使我们程序开发更简洁高效,但是有时一遍又一遍的重复性循环却让代码显得循环不堪。
这个时候我们就可以用迭代器来简化我们的循环遍历操作,下面我们创建一个迭代器类。
//迭代器
var Iterator=function(items,container){
//获取父容器,若container参数存在,并且可以获取该元素则获取,否则获取document
var container=container&&document.getElementById(container)||document,
//获取元素
items=container.getElementsByTagName(items),
//获取元素长度
length=items.length,
//当前索引值
index=0;
//缓存原生数组splice方法
var splice=[].splice;
return{
//获取第一个元素
first:function(){
index=0;
return items[index];
},
//获取最后一个元素
second:function(){
index=length-1;
return items[index];
},
//获取前一个元素
pre:function(){
if(--index>0){
return items[index];
}else{
index=0;
return null;
}
},
//获取后一个元素
next:function(){
if(++index<length){
return items[index];
}else{
index=length-1;
return null;
}
},
//对每一个元素执行某一个方法
get:function(num){
//如果num大于等于0再获取正向获取,否则逆向获取
index=num>=0?num%length:num%length+length;
console.log(index);
return items[index];
},
//对某一个元素执行某一个方法
dealEach:function(fn){
//第二个参数开始为回调函数中参数
var args=splice.call(arguments,1);
for (var i=0;i<length;i++) {
fn.apply(items[i],args);
}
},
//排他方式处理某一个元素
dealItem:function(num,fn){
//第三个参数开始为回调函数中参数
//用this.get方法设置index索引值
fn.apply(this.get(num),splice.call(arguments,2))
},
exclusive:function(num,allFn,numFn){
//对所有元素执行回调函数
this.dealEach(allFn);
//如果num类型为数组
if(Object.prototype.toString.call(num)==="[object Array]"){
//遍历num数组
for(var i=0;i<num.length;i++){
this.dealItem(num[i],numFn);
}
}else{
//处理第num个元素
this.dealItem(num,numFn);
}
}
}
}
页面元素如下:
<ul id="container">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
好了我们的迭代器就完成了,我们试着调用一下
var test=new Iterator("li","container");
//我们先试试获取元素
console.log(test.first());
console.log(test.pre());
console.log(test.next());
console.log(test.get(2000));
我们再来处理所有元素
test.dealEach(function(text,color){
this.innerHTML=text;
this.style.background=color;
},'背景变色','#dddddd');
接着我们选中前两个元素
test.exclusive([0,1],function(){
this.innerHTML='被排除的';
this.style.background='green';
},function(){
this.innerHTML='选中的';
this.style.background='red';
})
通过迭代器提供的接口方法就能轻易地访问聚合对象中的每一个元素。甚至不需要知道聚合对象的内部的具体结构。
数组迭代器
我们知道在低版本的IE下是不支持each方法的,那么我们就可以通过迭代器的思想定义一个数组迭代器来完成each操作
var eachArray=function(arr,fn){
for (var i=0;i<arr.length;i++) {
//依次执行回调函数,注意回调函数中传入的参数第一个为索引,第二个为索引对应的值
if(fn.call(arr[i],i,arr[i])===false){
break;
}
}
}
我们来测试一下
for(var arr=[],i=0;i<5;arr[i++]=i);
eachArray(arr,function(i,data){
console.log(i,data);
})
对象迭代器
对象迭代器与数组迭代器比较类似,但传入回调函数中的为对象的属性与对象的属性值
var eachObject=function(obj,fn){
for(var i in obj){
if(fn.call(obj[i],i,obj[i])===false){
break;
}
}
}
我们再来看看
var obj={a:1,b:2,c:3}
eachObject(obj,function(i,data){
console.log(i,data);
});
解决分支循环嵌套
当然我们也能用迭代器解决分支循环嵌套,比如我们使用canvas来处理图片像素绘制如下效果
页面元素如下:
<canvas id="canvas"></canvas>
<img src="img/test.jpg"/>
window.onload=function(){
//获取画布
var canvas=document.getElementsByTagName('canvas')[0],
//获取图片
img=document.images[0],
//获取并设置宽度
width=(canvas.width=img.width*2)/2,
//获取并设置高度
height=canvas.height=img.height,
//获取渲染上下文
ctx=canvas.getContext('2d');
//绘制图片
function dealImage(t,x,y,w,h,a){
//获取画布图片数据
var canvasData=ctx.getImageData(x,y,w,h);
//获取像素数据
var data=canvasData.data;
//遍历每组像素数据(4个数据表示一个像素点数据,分别代表红色、绿色、蓝色、透明度)
for (var i=0;i<data.length;i+=4) {
switch(t){
case 'red':
data[i+1]=0;
data[i+2]=0;
data[i+3]=a;
break;
case 'green' :
data[i]=0;
data[i+2]=0;
data[i+3]=a;
break;
case 'blue':
data[i]=0;
data[i+1]=0;
data[i+3]=a;
case 'gray':
var num=parseInt((data[i]+data[i+1]+data[i+2])/3);
data[i]=num;
data[i+1]=num;
data[i+3]=a;
break;
}
//绘制处理后的图片
ctx.putImageData(canvasData,width+x,y);
}
}
//为图片添加特效
dealImage('gray',0,0,width,height,255);
}
然而我们发现,这种逻辑并不是最优的,因为每一次遍历都要进行一次分支判断,假如有一张比较大的图片会产生很多不必要的消耗,但是我们可以将循环遍历抽象出来作为一个迭代器存在,每次循环都执行传入迭代器中的某一固定算法,对于特效算法我们可以设置在策略对象中实现,通过策略模式与迭代器模式的综合运用就可以解决分支判断问题
function dealImage(t,x,y,w,h,a){
var canvasData=ctx.getImageData(x,y,w,h),
data=canvasData.data;
//策略模式封装算法
var Deal=function(){
var method={
'default':function(i){
return method['gray'](i);
},
'red':function(i){
data[i+1]=0;
data[i+2]=0;
data[i+3]=a;
},
'green':function(i){
data[i]=0;
data[i+2]=0;
data[i+3]=a;
},
'gray':function(i){
data[i]=data[i+1]=parseInt(data[i+2]=(data[i]+data[i+1]+data[i+2])/3);
data[i+3]=a;
}
};
//主函数,通过给定类型返回对应滤镜算法
return function(type){
return method[type]||method['default'];
}
}();
//迭代器处理数据
function eachData(fn){
for (var i=0;i<data.length;i+=4) {
fn(i);
}
}
eachData(Deal(t));
ctx.putImageData(canvasData,width+x,y);
}
总结
通过迭代器我们可以顺序地访问一个聚合对象中的每一个元素。在开发中,迭代器极大简化了代码中的循环语句,使代码结构清晰紧凑,然而这些简化了的循环语句实质上隐形地移到了迭代器中。当然用迭代器去处理一个对象时,我们只需提供处理的方法,而不必去关心对象的内部结构,这也解决了对象的使用者与对象内部结构之间的耦合。当然迭代器的存在也为我们提供了操作对象的一个统一接口
也谢谢大家看到这里:)如果你觉得我的分享还可以请点击推荐,分享给你的朋友让我们一起进步~
好了以上就是本次分享的全部内容,本次示例参考自JavaScript设计模式一书,让我们一点点积累一点点成长,希望对大家有所帮助。
欢迎转载,转载请注明作者,原文出处。
再起航,我的学习笔记之JavaScript设计模式25(迭代器模式)的更多相关文章
- 再起航,我的学习笔记之JavaScript设计模式08(建造者模式)
我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 前几 ...
- 再起航,我的学习笔记之JavaScript设计模式09(原型模式)
我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 我们 ...
- 再起航,我的学习笔记之JavaScript设计模式11(外观模式)
经过一段时间的学习与分享,我们对创建型设计模式已经有了一定的认识,未来的一段时间里我们将展开新的篇章,开始迈入结构性设计模式的学习. 结构性设计模式与创建型设计模式不同,结构性设计模式更偏向于关注如何 ...
- 再起航,我的学习笔记之JavaScript设计模式14(桥接模式)
桥接模式 桥接模式(Bridge): 在系统沿着多个维度变化的同时,又不增加其复杂度并已达到解耦 从定义上看桥接模式的定义十分难以理解,那么我们来通过示例来演示什么是桥接模式. 现在我们需要做一个导航 ...
- 再起航,我的学习笔记之JavaScript设计模式17(模板方法模式)
模板方法模式 由模板方法模式开始我们正式告别结构型设计模式,开始行为型设计模式的学习分享 行为型设计模式用于不同对象之间职责划分或算法抽象,行为型设计模式不仅仅涉及类和对象,还涉及类或对象之间的交流模 ...
- 再起航,我的学习笔记之JavaScript设计模式20(策略模式)
策略模式 策略模式(Strategy):将定义的一组算法封装起来,使其相互之间可以替换.封装的算法具有一定的独立性,不会随客户端变化而变化. 其实策略模式在我们生活中可应用的地方还是比较多的,比如在商 ...
- 再起航,我的学习笔记之JavaScript设计模式22(访问者模式)
访问者模式 概念介绍 访问者模式(Visitor): 针对于对象结构中的元素,定义在不改变该对象的前提下访问结构中元素的新方法 解决低版本IE兼容性 我们来看下面这段代码,这段代码,我们封装了一个绑定 ...
- 再起航,我的学习笔记之JavaScript设计模式24(备忘录模式)
备忘录模式 概念介绍 备忘录模式(Memento): 在不破坏对象的封装性的前提下,在对象之外捕获并保存该对象内部的状态以便日后对象使用或者对象恢复到以前的某个状态. 简易分页 在一般情况下我们需要做 ...
- 再起航,我的学习笔记之JavaScript设计模式26(解释器模式)
解释器模式 概念介绍 解释器模式(Interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 获取元素在页面中的路径 我们都知道获取一个 ...
随机推荐
- BotVS数字货币现货交易类库
以下是BotVS数字货币现货交易类库模板,使用Python2语言实现 import types # 导入类型模块 import time # 导入时间模块 import platform # 版本信息 ...
- 国内5家云服务厂商 HTTPS 安全性测试横向对比
随着 Chrome.Firefox 等浏览器对 HTTPS 的重视,国内众多云服务厂商都相继提供 SSL 证书申购服务,但是大家有没有注意到一个细节,不同厂家申请的 SSL 证书,由于证书性能.功能差 ...
- node.js的fs核心模块读写文件操作 -----由浅入深
node.js 里fs模块 常用的功能 实现文件的读写 目录的操作 - 同步和异步共存 ,有异步不用同步 - fs.readFile 都不能读取比运行内存大的文件,如果文件偏大也不会使用readFil ...
- 日志log4j配置详情,日志log具体到你想不到
一.Log4j简介Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局). 1.LoggersLoggers组件在此系统中被分为五个级别:DEBU ...
- 49、html基础认识&常用标签(1)
从今天期我们进入前端的学习,先学习html,没有任何需要逻辑需要烧脑,只需要记忆.练习.练习.练习. 一.HTML初识 1.web服务本质 import socket def main(): sock ...
- JavaScript封装一个MyAlert弹出框
平时我们想要显示一些提示信息时会用到alert方法,alert是全局的一个方法,会短暂的中断程序,我们主要用来显示提示客户信息.但是这个方法有一定的局限性,而且本身样式也不够美观.于是我封装了一个实用 ...
- 团队作业4---第一次项目冲刺(ALpha)版本 第七天
一.Daily Scrum Meeting照片 二.燃尽图 三.项目进展 a.完成所有基础功能 b.正在进行测试调试 四.困难与问题 1.随着测试出现了大大小小的一些BUG,但是由于原来写的时候思维定 ...
- 201521123121 《Java程序设计》第3周学习总结
本周学习总结 书面作业 代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; public st ...
- 201521123042 《Java程序设计》第3周学习总结
1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2. 书面作 ...
- 201521123036 《Java程序设计》第1周学习总结
本周学习总结 本周的课是Java的入门.了解了Java的发展过程,运用平台,可跨平台的便利性.懂得jdk,jre,jvm的概念及区别.熟悉Java开发工具,掌握java程序的编译执行的详细过程. 书面 ...