zoukankan      html  css  js  c++  java
  • 04代理,迭代器

    代理模式

    • 为一个对象提供一个代用品或占位符。以便控制对他的访问;
    面向对象设计原则-单一职责原则
    • 就一个类(对象,函数)而言,应该仅有一个引起他变化的原因;(低耦合)

    代理和本体借口的一致性

    • 当不需要代理的时候可以替换回本体

    保护代理

    • 过滤请求;可以用于控制不同权限对象对目标对象的访问

    虚拟代理

    • 把一些开销很大的对象,延迟到真正需要的时候才创建;
    • 实现图片预加载
    var myImage = (function() {
      var imgNode = document.createElement('img');
      document.body.appendChild(imgNode);
      return function(src) {
        imgNode.src = src;
      };
    
    })();
    
    var proxyImage = (function() {
      var img = new Image;
      img.onload = function() {
        myImage(this.src);
      };
      return function(src) {
        myImage('picture/loading.jpg');
        img.src = src;
      }
    })();
    
    proxyImage('http://tp3.sinaimg.cn/1805666510/180/5718258464/1');
    
    • 实现合并请求
    var synchronousFile = function (id) {
      console.log('开始同步 ' + id);
    };
    
    var proxySynchronousFile = (function() {
      var cache = [], timer;
      return function(id) {
        cache.push(id);
        if(timer)
          return;
        timer = setTimeout(function() {
          synchronousFile(cache.join(','));
          clearTimeout(timer);
          timer = null;
          cache.length = 0;
        }, 2000);  //2秒延迟后一次性处理
      };
    })();
    
    var checkbox = document.getElementsByTagName('input');
    for(var i = 0, c; c = checkbox[i++];) {
      c.onclick = function() {
        if(this.checked === true)
          proxySynchronousFile(this.id);
      }
    };
    
    

    在堕性加载中的应用

    var miniConsole = (function(){
      var cache = [];
      var handler = function( ev ){
        if ( ev.keyCode === 13 ){ //enter
          var script = document.createElement( 'script' );
          script.onload = function(){
            for ( var i = 0, fn; fn = cache[ i++ ]; ){
              fn();
            }
          };
          script.src = 'log.js';
          document.getElementsByTagName( 'head' )[0].appendChild(script);
          document.body.removeEventListener( 'keydown', handler );
        }
      };
      document.body.addEventListener( 'keydown', handler, false );
      return {
        log: function(){
          var args = arguments;
          cache.push( function(){
            return miniConsole.log.apply( miniConsole, args );  //缓存,当真正加载log.js再执行;
          });
        }
      }
    })();
    
    
    miniConsole.log(0);
    miniConsole.log(1);
    //按下enter
    
    // log.js 代码
    miniConsole = {
      log: function(){
      // 真正代码略
        console.log( Array.prototype.join.call( arguments ) );
      }
    };
    

    缓存代理

    • 为一些开销大的运算结果提供暂时的存储
    var mult = function () {
      var a = 1;
      for(var i = 0, len = arguments.length; i < len; i++)
        a = a * arguments[i];
      return a;
    };
    
    var proxyMult = (function() {
      var cache = {};
      return function() {
        var args = [].join.call(arguments, ',');
        if(args in cache)
          return cache[args]
        return cache[args] = mult.apply(this, arguments);
      };
    })();
    
    proxyMult(3,6,8);
    
    • 用于ajax异步请求: 如分页实现时讲数据缓存,下次请求同一页再输出;

    利用高阶函数动态创建代理

    • 如将上面的proxyMult修改,使以后类似计算的缓存代理都用同一个函数产生
    var createProxyFactory = function(fn) {
      var cache = {};
      return function() {
        var args = [].join.call(arguments, ',');
        if(args in cache)
          return cache[args];
        return cache[args] = fn.apply(this, arguments);
      }
    };
    
    var proxyMult = createProxyFactory(mult);
    
    

    其他代理

    • 防火墙代理:控制网络资源的访问;

    • 远程代理:为一个对象在不同的地址空间提供局部代表;

    • 保护代理:用于对象应该有不同访问权限的情况;

    • 智能引用代理:取代简单的指针,在访问对象时执行一些附加操作;

    • 写时即复制代理:通常用于复制一个庞大对象的情况;他延迟了复制的过程,当对象真正被修改时才进行复制;

    • 在编写业务代码的时候往往不需要预先设置使用代理模式,当真正发现不方便直接访问某个对象的时候再使用;

    迭代器模式

    • 顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示的方法;
    • 现在流行的大部分语言都有内置的迭代器实现;JS中如Array.prototype.forEach

    内部迭代器

    • 内部已经定义好了迭代规则
    var each = function (arr, callback) {
      for(var i = 0, len = arr.length; i < len; i++)
        callback.call(arr, i, arr[i]); //这里可以修改对象
    };
    
    each([1,2,3], function(index, value) {
      console.log(this,index,value);
    });
    

    外部迭代器

    • 必须显示地请求迭代下一个元素;增加了复杂度,但也增强累迭代器的灵活性;可以手工控制迭代过程;
    var Iterator = function(obj) {
      var current = 0, len = obj.length;
      var next = function() {
        current++;
      }
      var isDone = function() {
        return current >= len; //如果length会自动修改那直接使用
      }
      var getCurrentIten = function() {
        return obj[current];
      }
      return {
        next: next,
        isDone: isDone,
        getCurrentIten: getCurrentIten
      }
    };
    //一个比较数组相等的例子
    var compare = function(iterator1, iterator2) {
      while(!iterator1.isDone() || !iterator2.isDone()) {
        if(iterator1.getCurrentIten() !== iterator2.getCurrentIten())
          throw new Error('不相等');
        iterator1.next();
        iterator2.next();
      }
      console.log('相等');
    };
    
    compare(Iterator([0,1,2]), Iterator([0,1,2]));
    

    另一个迭代器实现

    var Iterator = function (items, container) {
      var container = container && document.getElementById(container) || document.body,
          items = container.getElementsByTagName(items),
          len = items.length,
          index = 0,
          splice = [].splice;
      return {
        first: function () {
          index = 0;
          return items[index];
        },
        second: function () {
          index = len - 1;
          return items[index];
        },
        pre: function () {
          if(--index > 0)
          	return items[index];
          else {
          	index = 0;
          	return null;
          }
        },
        next: function () {
          if(++index < len) 
          	return items[index]
          else {
          	index = len - 1;
            return null;
          }
        },
        get: function (num) {
          index = num >= 0 ? num % len : num % len + len;
          return items[index];
        },
        dealEach: function (fn) {
          var args = splice.call(arguments, 1);
          for(var i = 0; i < len; i++) {
            fn.apply(items[i], args);
          }
        },
        dealItem: function (num, fn) {
          fn.apply(this.get(num), splice.call(arguments, 2))
        },
        exclusive: function (num, allFn, numFn) {
          this.dealEach(allFn);
          if(Object.prototype.toString.call(num) === '[object Array]') {
          	for(var i = 0, l = num.length; i < l; i++) {
          	  this.dealItem(num[i], numFn);
          	} 
          } else {
            this.dealItem(num, numFn);
          }
        }
      }
    };
    
    var demo = new Iterator('li', 'container');
    console.log(demo.first());
    console.log(demo.pre());
    console.log(demo.next());
    console.log(demo.get(3));
    demo.dealEach(function(text, color) {
      this.innerHTML = text;
      this.style.background = color;
    }, 'test', 'pink');
    
    demo.exclusive([2,3], function () {
      this.innerHTML = '被排除的';
      this.style.background = 'green';
    }, function () {
      this.innerHTML = '被选中的';
      this.style.background = 'red';
    })
    
    

    迭代类数组和字面量对象

    • 实际上只要聚合对象拥有length属性并可以下标访问就可以被迭代

    应用例子

    • 比如一个功能里使用try-catch,if-else等根据实际情况尝试不同的执行函数;
    • 可以将所有要尝试的函数单独分开并设置尝试执行失败返回false;
    • 将所有要尝试的函数通过高迭代器执行,以后增加新的执行函数,只要按照一定顺序迭代就可以;
    var iterator = function() {
      for(var i = 0, fn; fn = arguments[i++];) {
        var result = fn();
        if(result !== false)
          return result;
      }
    };
    
    iterator(fn1, fn2, fn3, fn4);
    

    同步变量迭代器

    //同步变量
    var A = {
      common: {},
      client: {
        user: {
          username: '',
          uid: ''
        }
      },
      server: {}
    };
    
    //同步变量迭代取值器
    var AGetter = function (key) {
      if(!A) return;
      var result = A;
      key = key.split('.');
      for(var i = 0, l = key.length; i < l; i++) {
        if(result[key[i]] !== undefined) {
          result = result[key[i]];
        } else {
          return;
        }
      }
      return result;
    };
    
    //同步变量迭代赋值器
    var ASetter = function (key, val) {
      if(!A) return;
      var result = A;
      key = key.split('.');
      for(var i = 0, l = key.length; i < l; i++) {
        if (result[key[i]] === undefined) {
          result[key[i]] = {};
        }
        if (!(result[key[i]] instanceof Object)) {
          throw new Error('A. ' + key.splice(0, i + 1).join('.') + ' is not Object');
          return false;
        }
        result = result[key[i]];
      }
      return result[key[i]] = val;
    };
    
    console.log(AGetter('client.user.username'));
    console.log(ASetter('client.server.new', 'on'));
    
  • 相关阅读:
    C# 6.0:在catch和finally中使用await
    C# 6.0:Expression – Bodied Methods
    C# 6.0:Auto-Property initializer
    C# 6.0:String Interpolation
    【转】http://www.cnblogs.com/yuzukwok/p/3884377.html
    ThoughtWorks面试题(标记给自己看)
    C# 强制关闭当前程序进程(完全Kill掉不留痕迹)
    (转)C#编程中的66个好习惯
    (转)解决WINDOWS 程序界面闪烁问题的一些经验
    C#利用反射动态绑定事件
  • 原文地址:https://www.cnblogs.com/jinkspeng/p/4582448.html
Copyright © 2011-2022 走看看