【学习笔记javascript设计模式与开发实践(迭代器模式)----7】

第7章 迭代器模式

迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代器模式可以把迭代的过程从业务逻辑分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素。

7.1 jQuery中的迭代器

迭代器模式无非就是循环访问聚合对象中的各个元素。比如jQuery中的$.each函数,其中回调函数中的参数i为当前索引,n为当前元素,如下:

$.each([1,2,3],function(i,n){
  console.log(‘当前下标为:’:+i);
  console.log(‘当前值为:’+n);
});

7.2 实现自己的迭代器

现在我们可以自己来实现一个each函数,each函数接受2个参数,第一个为被循环的数组,第二个为循环中的每一步后将被触发的回调函数

var each = function(ary,callback){
  for(var i=0,l=ary.length;i<l;i++){
    callback.call(ary[i],i,ary[i]);
   }
}
each([1,2,3,4],function(i,n){
   alert([i,n]);
})

7.3 内部迭代器和外部迭代器

迭代器可以分为内部迭代和外部迭代器,它们有各自的适用场景。这一节我们将分别讨论这两种迭代器。

1.       内部迭代器

我们刚刚编写的each函数属于内部迭代器,each函数的内部已经定义好了迭代规则,它完全接手整个迭代过程,外部只需要一次初始调用。

内部迭代器在调用的时候非常方便,外界不用关心迭代器的内部实现,跟迭代器的交互也仅仅是一次初始调用,但这也刚好蚋部迭代器的缺点,由于内部迭代器的迭代规则已被提前规定,上面的each函数就无法同时迭代2个数组

比如现在有个需求,要判断2个数组里元素的值是否完全相等,如果不改写each函数本身的代码,我们能够入手的地方似乎只剩下each回调函数,如下:

var compare =function(arr1,arr2){
 if(arr1.length!=arr2.length){
     throw new Error(‘ar1和ar2不相等’);
 }
 each(arr1,function(i,n){
      if(n!=arr2[i]){
       throw new Error(‘ary1和ary2不相等’);
     }
 });
 alert(‘相等’);
}
compare([1,2,3],[1,2,4])//不等

说实话,这个compare函数一点都算不上好看,我们目前能够顺利完成需求,还要感谢javascript里可以把函数当作参数传递的特性。但在其他语言中未必就能如此幸运。在一些没有闭包的语言中,内部迭代器本身的实现也相当复杂,如C语言中的内部迭代器是用函数指针来实现的,循环处理所需要的数据都要以参数的形式明确地从外面传递进去。

2.       外部迭代器

外部迭代器必须显式地请求迭代下一个元素。

外部迭代器增加了一些调用的复杂度,但相对也增强了迭代器的灵活性,我们可以手工控制迭代的过程或者顺序。

下面这个外部迭代器的实现来自《松本行弘的程序世界》用Ruby写成,这里我们翻译成js:

var Iterator = function(obj){
    var current = 0;
    var next = function(){
            current+=1;
        }
    var isDone = function(){
            return   current>=obj.length;
        }
    var getCurrentItem = function(){
            return obj[current];
       }
    return {
           next:next,
           isDone:isDone,
           getCurrentItem: getCurrentItem
    }
}

再看看如何改写compare函数:

var compare =function(iterator1,iterator2){
   while(!iterator1.isDone() &&!iterator2.isDone()){
       if(iterator1.getCurrentItem() !==iterator2.getCurrentItem()){
               throw new Error(“iterator1和iterator2不相等’);
       }
       iterator1.next();
       iterator2.next();
   }
}
 
var iterator1 =Iterator([1,2,3]);
var iterator2 =Iterator([1,2,3]);
compare(iterator1,iterator2);//输出<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>

外部迭代器虽然调用方式相对复杂,但它的适用更广,也能满足更多变的需求。内部迭代器和外部迭代器在实际生产中没有优劣之分,究竟使用哪个要根据需求场景而定。

7.4 迭代类数组对象和字面量对象

迭代器模式不仅可以迭代数组,还可以迭代一些类数组对象。比如arguments、{“0”,”a”,”1”:”b”}等。能过上面的代码可以观察到,无论是内部迭代器还是外部迭代器,只要迭代的聚合对象拥有length属性而且可能用下标访问,那它就可以被迭代。

在javascript中,for in 语句可以用来迭代普通字面量对象。jQuery中提供了$.each函数来封装各种迭代行为:

$.each = function(obj,callback){
  var value,i=0,length=obj.length,
  isArray = isArraylike(obj);
  if(isArray){
     for(;i<length;i++){
          value = callback.call(obj[i],i,obj[i]);
          if(value===false){
          break;
     }
  }else{
     for( i in obj){
         value = callback.call(obj[i],i,obj[i]);
         if(value===false){
               break;
         }
     }  //end for
  }//end else
  return obj;
}


7.5 倒序迭代器

由于GoF中对迭代器的模式的定义非常松散,所以我们可以有多种多样的迭代器实现。总的来说,迭代器模式提供了循环访问一个聚合对象中每个元素的方法,但它没有规定我们以顺序、倒序还是中序来循环遍历聚合对象

倒序遍历对象:

var reverseEach = function(ary,callback){
  for(var l =ary.length-1;l>=0;l--){
      callback(l,ary[l]);
  }
}
reverseEach([0,1,2], function(i,n){
  console.log(n);
}

7.6 中止迭代器

迭代器可以像普通for循环中的break一样,提供一种跳出循环的方法。在上一节中的each函数里有这样一句:

if(value == false){
   break;
}

这句代码的意思是,约定如果回调函数的执行结果返回false,则提前终止循环。下面我们把之前的each函数改写一下:

var each = function(ary,callback){
  for(vari=0,l=ary.length;i<l;i++){
    if(callback(i,ary[i])===false){
      break;
    }
  }
}
 
each([1,2,3,4,5],function(i,n){
  if(n>3){
      return false; //n大于 3终止循环
  }
   console.log(n);
});

7.7 迭代器模式的应用举例

作者曾经要重构一个模块的代码,发现下面的这段代码,它的目的是根据不同的浏览器获取相应的上传组件对象:

var getUploadObj = function(){
  try{
     return new ActiveXObject(‘TXFINActiveX.FTNUpload”); //ie上传
  }catch(e){
     if(supportFlash()){
          var str = ‘<object type=”application/x-shockwave-flash”></object>’;
          return $(str).appendTo($(‘body’));
     }else{
          var str = ‘<input name = “file” type=”file”/>’;
          return $(str).appendTo($(‘body’));
     }
   }
}

现在来梳理一下问题,目前一共有3种可能上传的方式,我们不知道目前正在使用的浏览器支持哪几种。就好比我们有一个钥匙串,其中共有3把钥匙,我们想打开一扇门但是不知道用哪把钥匙,于是从第一把开始,迭代钥匙串进行尝试,直到找到正确的钥匙为止。

同样,我们把每种获取upload对象的方法都封装在各自的函数里,然后使用一个迭代器迭代获取这些upload对象,直到获取到一个可用的为止:

var getActiveUploadObj = function(){
   try{
       return new ActiveXObject(“TXFNActiveX.FTNUpload”);
    }catch(e){
       return false;
    }
}
 
var getFlashUploadObj = function(){
  if(supportFlash()){
     var str = ‘<object type=”application/x-shockwave-flash”></object>’;
     return $(str).appendTo($(‘body’));
   }
  return false;
}
 
var getFormUploadObj = function(){
var str = ‘<inputname = “file” type=”file” />’;
return$(str).appendTo($(‘body’));
}

在上述的3个函数中我们都有同一个约定,如果该函数里面的upload对象是可用的,则让函数返回该对象,反之返回false,提示迭代器继续往后进行迭代

var iteratorUploadObj = function(){
   for(var i=0,fn;fn=arguments[i++];){
       var uploadObj =fn();
       if(uploadObj!==false){
          return uploadObj;
      }
   }
}
var uploadObj = iteratorUploadObj(getActiveUploadObj,getFlashUploadObj, getFormUploadObj);

如后期还要支持html5的或是webkit的只要添加相应的函数就OK 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值