zoukankan      html  css  js  c++  java
  • js设计模式-迭代器模式

    迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。如each函数。
    手动实现一个

    var each = function( ary, callback ){
    for ( var i = 0, l = ary.length; i < l; i++ ){
    callback.call( ary[i], i, ary[ i ] ); // 把下标和元素当作参数传给callback 函数
    }
    };
    each( [ 1, 2, 3 ], function( i, n ){
    alert ( [ i, n ] );
    });

    一. 内部迭代器和外部迭代器

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

    内部迭代器在调用的时候非常方便,外界不用关心迭代器内部的实现,跟迭代器的交互也仅仅是一次初始调用,但这也刚好是内部迭代器的缺点。由于内部迭代器的迭代规则已经被提前规定,上面的each 函数就无法同时迭代2 个数组了。
    外部迭代器必须显式地请求迭代下一个元素。如要判断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 ];
    };
      return {
        next: next,
        isDone: isDone,
        getCurrItem: getCurrItem
      }
    };
    var compare = function( iterator1, iterator2 ){
      while( !iterator1.isDone() && !iterator2.isDone() ){
        if ( iterator1.getCurrItem() !== iterator2.getCurrItem() ){
          throw new Error ( 'iterator1 和iterator2 不相等' );
        }
        iterator1.next();
        iterator2.next();
      }
      alert ( 'iterator1 和iterator2 相等' );
    }
    var iterator1 = Iterator( [ 1, 2, 3 ] );
    var iterator2 = Iterator( [ 1, 2, 3 ] );
    compare( iterator1, iterator2 ); // 输出:iterator1 和iterator2 相等

    迭代器模式不仅可以迭代数组,还可以迭代一些类数组的对象。比如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 ) { // 迭代object 对象
          value = callback.call( obj[ i ], i, obj[ i ] );
          if ( value === false ) {
            break;
          }
        }
      }
      return obj;
    };

    二. 倒叙迭代

    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 ); // 分别输出:2, 1 ,0
    });

    三. 中止迭代

    var each = function( ary, callback ){
      for ( var i = 0, l = ary.length; i < l; i++ ){
        if ( callback( i, ary[ i ] ) === false ){ // callback 的执行结果返回false,提前终止迭代
          break;
        }
      }
    };
    each( [ 1, 2, 3, 4, 5 ], function( i, n ){
      if ( n > 3 ){ // n 大于3 的时候终止循环
        return false;
      }
      console.log( n ); // 分别输出:1, 2, 3
    });  
    四.应用(根据不同的浏览器获取相应的上传组件对象)

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

    var getActiveUploadObj = function(){
      try{
        return new ActiveXObject( "TXFTNActiveX.FTNUpload" ); // IE 上传控件
      }catch(e){
        return false;
      }
    };
    var getFlashUploadObj = function(){
      if ( supportFlash() ){ // supportFlash 函数未提供
        var str = '<object type="application/x-shockwave-flash"></object>';
        return $( str ).appendTo( $('body') );
      }
      return false;
    };
    var getFormUpladObj = function(){
      var str = '<input name="file" type="file" class="ui-file"/>'; // 表单上传
      return $( str ).appendTo( $('body') );
    };

    在getActiveUploadObj、getFlashUploadObj、getFormUpladObj 这3 个函数中都有同一个约定:如果该函数里面的upload 对象是可用的,则让函数返回该对象,反之返回false,提示迭代器继续往后面进行迭代。

    所以我们的迭代器只需进行下面这几步工作:

     提供一个可以被迭代的方法,使得getActiveUploadObj,getFlashUploadObj 以及getFlashUploadObj依照优先级被循环迭代。

     如果正在被迭代的函数返回一个对象,则表示找到了正确的upload 对象,反之如果该函数返回false,则让迭代器继续工作。

    迭代器代码如下:

    var iteratorUploadObj = function(){
      for ( var i = 0, fn; fn = arguments[ i++ ]; ){  // 这里的arguments是那三个函数,每次将函数赋给fn,然后通过fn()调用函数。 这里的for循环语句,意思是声明了i 和 fn。
        var uploadObj = fn();
        if ( uploadObj !== false ){
          return uploadObj;
        }
      }
    };
    var uploadObj = iteratorUploadObj( getActiveUploadObj, getFlashUploadObj, getFormUpladObj );
  • 相关阅读:
    真正的e时代
    在线手册
    UVA 10616 Divisible Group Sums
    UVA 10721 Bar Codes
    UVA 10205 Stack 'em Up
    UVA 10247 Complete Tree Labeling
    UVA 10081 Tight Words
    UVA 11125 Arrange Some Marbles
    UVA 10128 Queue
    UVA 10912 Simple Minded Hashing
  • 原文地址:https://www.cnblogs.com/aimeeblogs/p/12197381.html
Copyright © 2011-2022 走看看