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'));
    
  • 相关阅读:
    教程:在 Visual Studio 中开始使用 Flask Web 框架
    教程:Visual Studio 中的 Django Web 框架入门
    vs2017下发现解决python运行出现‘No module named "XXX""的解决办法
    《sqlite权威指南》读书笔记 (一)
    SQL Server手工插入标识列
    hdu 3729 I'm Telling the Truth 二分图匹配
    HDU 3065 AC自动机 裸题
    hdu 3720 Arranging Your Team 枚举
    virtualbox 虚拟3台虚拟机搭建hadoop集群
    sqlserver 数据行统计,秒查语句
  • 原文地址:https://www.cnblogs.com/jinkspeng/p/4582448.html
Copyright © 2011-2022 走看看