zoukankan      html  css  js  c++  java
  • 高级技巧

    一,高级函数
    1,安全的类型检测
      safari中tepeof操作符对正则表达式返回function
      instanceof存在多个全局作用域(包含多个frame)时,frame中定义的变量不能再其他的frame中使用
      在任何值上调用Object原生的toString()方法,返回一个[object NativeConstructorName]格式的字符串
      每个类的内部都有一个[[class]]属性,指定了上述字符串中的构造函数名
      检测是否为原生函数
      function isFunction(value){
        return Object.prototype.toString.call(value) == "[object Function]";
      }
      检测是否为正则表达式
      function isRegExp(value){
        return Object.prototype.toString.call(value) == "[object RegExp]";
      }
      对于IE中以COM对象形式实现的任何函数,以上都会返回false
      开发人员定义的任何构造函数都将返回[object Object];用于区别原生与非原生的Javascript对象
    2,作用域安全的构造函数
      当使用new操作符时,构造函数内用到的this对象会指向新创建的对象实例
      当没有使用new操作符,直接使用构造函数如Person(),this会映射到全局对象window上,导致错误对象属性的意外增加
      创建一个作用域安全的构造函数

        function Person(name,age,job){
          if(this instanceof Person){
            this.name = name;
            this.age = age;
            this.job = job;
          }else{
            return new Person(name,age,job);
          }
        }

      此时锁定了构造函数的环境,如果不使用原型链会破坏使用这个构造函数窃取模式的继承
      使用构造函数窃取结合使用原型链或者寄生组合可以解决这个问题

      function Polygon(sides){
        if(this instanceof Polygon){
          this.sides = sides;
          this.getArea = function(){};
        }else{
          return new Polygon();
        }
      }
      function Rectangle(width,height){
        Polygon.call(this,2);
        this.width = width;
        this.height = height;
        this.getArea = function(){return this.width * this.height;};
      }
      Rectangle.prototype = new Polygon();

    3,惰性载入函数
      表示函数执行的分支仅会发生一次,if语句
      1)在函数被调用时再处理函数

        function createXHR(){
          if(typeof XMLHttpRequest != "undefined"){
            createXHR = function(){
              return new XMLHttpRequest();
            };
          }else if(typeof AcitveXObject != "undefined"){
            createXHR = function(){
              if(typeof argument.callee.activeXString != "String"){
                var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i,len;
                for(i=0,len=versions.length;i<len;i++){
                  new ActiveXObject(versions[i]);
                  argument.callee.activeXString = versions[i];
                  break;
                }catch(ex){
                  //skip
                }
              }
              return new ActiveXObject(argument.callee.activeXString);
            };
        }else{
          createXHR = function(){
            throw new Error("NO XHR object available");
          };
        }
        return createXHR();
      }

      2)在声明函数时指定适当的函数,第一次调用函数时就不会损失性能,在代码首次加载时会损失性能
      创建匿名,自执行的函数

        var createXHR = (function(){
          if(typeof XMLHttpRequest != "undefined"){
            return function(){
              return new XMLHttpRequest();
            };
          }else if(typeof ActiveXObject != "undefined"){
            return function(){
              if(typeof argument.callee.activeXString != "string"){
                var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i,len;
                for(i=0,len=versions.length;i<len;i++){
                  try{
                    new ActiveXObject(versions[i]);
                    argument.callee.activeXString = versions[i];
                    break;
                  }catch(ex){
                    //skip
                  }
                }
              }
              return new ActiveXObject(argument.callee.activeXString);
            };
        }else{
          return function(){
            throw new Error("NO XHR object available")
          };
        }
      })();

    4,函数绑定
      创建一个函数,可以在特定的this环境中以指定参数调用另一个函数,常常和回调函数与事件处理程序一起使用,将函数作为变量传递的同时保留代码执行环境
      将函数绑定到指定环境的函数,这个函数叫做bind(),接受一个函数和一个环境,返回一个在给定环境中调用给定函数的函数,所有参数原封不动的传递过去
      function bind(fn,context){
        return function(){
          return fn.apply(context,argument);
        };
      }
      argument是内部函数的而非bind()函数的
      使用自定义的bind()函数,
      var handler = {
        message:"Event handlers",
        handleClick:function(event){alert(this.message + ":" + event.type);}
      };
      var btn = document.getElementById("my-btn");
      EventUtil.addhandler(btn,"click",bind(handler.hangleClick,handler));
      原生的bind()方法,在ECMAscript中定义,传人作为this值的对象
      EventUtil.addhandler(btn,"click",handler.handleClick.bind(handler));
    5,函数的柯里化
      用于创建已经设置好了一个或多个参数的函数,基本方法,使用一个闭包返回一个函数,返回的函数还需要设置传人的参数
      创建步骤,调用另一个函数并为它传人要柯里化的函数和必要的参数

      function curry(fn){
        var args = Array.prototype.slice.call(arguments,1);
        return function(){
          var innerArgs = Array.prototype.slice.call(arguments);
          var finalArgs = args.concat(innerArgs);
          return fn.apply(null,finalArgs);
        };
      }
      function add(num1,num2){return num1+num2;}
      var curriedAdd = curry(add,5);
      alert(curriedAdd(3))
      var curriedAdd = curry(ass,6,10);
      alert(curredAdd());

      函数柯里化可以作为函数绑定的一部分包含在其中,构造出更为复杂的bind()函数

      function bind(fn,context){
        var args = Array.prototype.slice.call(arguments,2);
        return function(){
          var innerArgs = Array.prototype.slice.call(arguments);
          var finalArgs = args.concat(innerArgs);
          return fn.apply(context,finalArgs);
        };
      }
      除了event对象额外给事件处理程序传递参数时,
      var handler = {
        message:"Event Handler";
        handleClick:function(name,event){
          alert(this.message + ":" + name + ":" + event.type);
        }
      };
      var btn = document.getElementById("my-btn");
      EventUtil.addHandler(btn,"click",bind(handler.handleClick,handler,"my-btn"));
      EventUtil.addHandler(btn,"click",handler.handleClick.bind(handler,"my-btn"));

    二,防篡改对象
    1,不可扩展对象
      var person = {name:"Nicholas"};
      Object.preventExtensions(person);
      阻止对象的扩展,不能再添加属性和方法,可以修改删除已有成员
      Object.isExtensible(person);确定person是否可以扩展
    2,密封的对象
      密封对象不可扩展,已有成员的[[Configurable]]特性被修改为false,不能删除属性和方法,属性值可以修改
      Object.seal(person);密封对象
      Object.isSeal(person);确定person是否被密封
    3,冻结的对象
      冻结的对象既不可扩展,又是密封的,而且对象数据属性[[Writable]]特性被设置为false,定义[[Set]]函数,访问器属性仍然是可写的
      Object.freeze(person);冻结对象
      Object.isFrozen(person);确定对象是否冻结
    三,高级定时器
    1,重复的定时器
      1)某些间隔会被跳过,2)多个定时器的代码执行之间的间隔可能会比预期小
      避免上述问题,使用链式setTimeout()调用

      setTimeout(function(){
        setTimeout(argument.callee,interval);
      },interval);
      setTimeout(function(){
        var div = document.getElementById("myDiv");
        left = parseInt(div.style.left) + 5;
        div.style.left = left + "px";
        if(left < 200){
          setTimeout(argument.callee,50);
        }
      },50);

    2,Yielding Processes
      长时间运行脚本的制约,如果代码运行超过特定的时间或者特定语句数量,会弹出对话框
      原因有二,过长的,过深嵌套的函数调用或者是进行大量处理的循环,
      当发现某个循环占用了大量时间,可是使用定时器分割这个循环,叫做数组分块
      基本模式

      setTimeout(function(){
        //取出下一个条目并处理
        var item = array.shift();
        process(item);
        //若还有条目,再设置另一个定时器
        if(array.length>0){
          setTimeout(arguments.callee,100);
        }
      },100);

      实现数组分块,使用下列函数

      function chunk(array,process,context){
        setTimeout(function(){
          var item = array.shift();
          process.call(context,item);
          if(array.length > 0){
            setTimeout(arguments.callee,100);
          }
        },100);
      }

    3,函数节流
    思想是某些代码不可以在没有时间间断的情况连续重复执行,第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码
    第二次调用该函数时,它会清除前一次的定时器并设置另一个
    基本形式

      var processor = {
        timeoutID:null;
        //实际进行处理的方法
        performProcessing:function(){
          //实际执行的代码
        },
        //初始化处理调用的方法
        process:function(){
          clearTimeout(this.timeoutID);
          var that = this;
          this.timeoutID = setTimeout(function(){
            that.performProcessing();
          },100);
        }
      };
      processor.process();

    化简模式
      function throttle(method,context){
        clearTimeout(method.tid);
        method.tid = setTimeout(function(){
          method.call(context);
        },100);
      }
      resize事件,window.onresize = function(){};
        function resizeDIv(){
          var div = document.getElementById("myDIv");
          div.style.height = div.offsetWidth + "px";
        }
        window.onresize = function(){throttle(resizeDIv);};
    四,自定义事件
    自定义事件的基本模式

      function EventTarget(){this.handlers = {};}
      EventTarget.prototype = {
        constructor:EventTarget,
        addHandler:function(type,handler){
          if(typeof this.handlers[type] == "undefined"){
            this.handlers[type] = [];
          }
          this.handlers[type].push(handler);
        },
        fire:function(event){
          if(!event.target){
            event.target = this;
          }
          if(this.handlers[event.type] instanceof Array){
            var handlers = this.handlers[event.type];
            for(var i=0,len=handlers.length;i<len;i++){
              handlers[i](evnet);
            }
          }
        },
        removeHandler:function(type,handler){
          if(this.handlers[type] instanceof Array){
            var handlers = this.handlers[type];
            for(var i=0,len=handlers.length;i<len;i++){
              if(handlersp[i] === handler){
                break;
              }
            }
            handlers.splice(i,1);
          }
        },
       };

      使用自定义事件
      function handleMessage(event){
        alert("Message received:" + event.message);
      }
      var target = new EventTarget();
      target.addHandler("message",handleMessage);
      target.fire({type:"message",message:"hellod"});
      target.removeHandler("message",handleMessage);
      target.fire({type:"message",message:"hello"});
      其他对象可以继承EventTarget对象
      function Person(name,age){
        EventTarget.call(this);
        this.name = name;
        this.age = age;
      }
      inheritProtetype(Person,EventTarget);
      Person.prototype.say=function(message){
        this.fire({type:"message",message:message});
      };
      使用方法
      function handleMessage(event){
        alert(event.target.name + "say" + event.target);
      }
      var person = new Person("Nicholas",29);
      person.addHandler("message",handleMessage);
      person.say("Hi,there");
    五,拖放

      var DragDrop = function(){
        var dragging = null;
        function handleEvent(event){
          //获取事件和目标
          event = EventUtil.getEvent(event);
          var target = EventUtil.getTarget(event);
          //确定事件类型
          switch(event.type){
            case "mousedown":
              if(target.className.indexOf("draggable") > -1){dragging = target};
              break;
            case "mousemove":
              if(dragging != null){
                //指定位置
                dragging.style.left = event.clientX + "px";
                dragging.style.top = event.clientY + "px";
              }
              break;
            case "mouseup":
              dragging = null;
              break;
          }
        }
        //公共接口
        return{
          enable:function(){
            EventUtil.addHandler(document,"mousedown",handleEvent);
            EventUtil.addHandler(document,"mousemove",handleEvent);
            EventUtil.addHandler(document,"mouseup",handleEvent);
          },
          disable:function(){
            EventUtil.addHandler(document,"mousedown",handleEvent);
            EventUtil.addHandler(document,"mousemove",handleEvent);
            EventUtil.addHandler(document,"mouseup",handleEvent);
          },
        };
      }();

    1,修缮拖动功能

      var DragDrop = function(){
        var dragging = null,
        diffX = 0;,
        diffY = 0;
        function handleEvent(event){
          event = EventUtil.getEvent(event);
          var target = EventUtil.getTarget(event);
          switch(event.type){
            case "mousedown":
              if(target.className.indexOf("draggable") > -1){
                dragging = target;
                diffX = event.clientX - target.offsetLeft;
                diffY = event.clientY - target.offsetTop;
              }
              break;
            case "mousemove":
              if(dragging != null){
                dragging.style.left = (event.clientX-fiffX) + "px";
                dragging.style.top = (event.clientY - fiffY) + "px";
              }
              break;
            case "mouseup":
              dragging = null;
              break;
          }
        }
        return{
          enable:function(){
            EventUtil.addHandler(document,"mousedown",handleEvent);
            EventUtil.addHandler(document,"mousemove",handleEvent);
            EventUtil.addHandler(document,"mouseup",handleEvent);
          },
          disable:function(){
            EventUtil.addHandler(document,"mousedown",handleEvent);
            EventUtil.addHandler(document,"mousemove",handleEvent);
            EventUtil.addHandler(document,"mouseup",handleEvent);
          }
        };
      }();

    2,添加自定义事件

      var DragDrop = function(){
        var dragdrop = new EventTarget(), 
        dragging = null,
        diffX = 0;,
        diffY = 0;
        function handleEvent(event){
          event = EventUtil.getEvent(event);
          var target = EventUtil.getTarget(event);
          switch(event.type){
            case "mousedown":
              if(target.className.indexOf("draggable") > -1){
                dragging = target;
                diffX = event.clientX - target.offsetLeft;
                diffY = event.clientY - target.offsetTop;
                //触发dragstart
                dragdrop.fire({type:"dragstart",target:dragging,x:event.clientX,y:event.clientY});
              }
              break;
            case "mousemove":
              if(dragging != null){
                dragging.style.left = (event.clientX-fiffX) + "px";
                dragging.style.top = (event.clientY - fiffY) + "px";
                //触发自定义事件
                dragdrop.fire({type:"drag",target:dragging,x:event.clientX,y:clientY});
              }
              break;
            case "mouseup":
              //触发fragend事件
              dragdrop.fire({type:"dragend",target:dragging,x:event.clientX,y:event.clientY});
              dragging = null;
              break;
            }
        }
    
        dragdrop.enable=function(){
          EventUtil.addHandler(document,"mousedown",handleEvent);
          EventUtil.addHandler(document,"mousemove",handleEvent);
          EventUtil.addHandler(document,"mouseup",handleEvent);
        };
        dragdrop.disable=function(){
          EventUtil.addHandler(document,"mousedown",handleEvent);
          EventUtil.addHandler(document,"mousemove",handleEvent);
          EventUtil.addHandler(document,"mouseup",handleEvent);
        };
        return dragdrop;
      }();
      DragDrop.addHandler("dragstart",function(event){
        var status = document.getElementById("status");
        status,innerHTML = "Started dragging " + event.target.id;
      });
      DragDrop.addHandler("drag",function(event){
        var status = document.getElementById("status");
        status.innerHTML += "<br/>Dragged " + event.target.id + " to("+event.x+","+event.y+")";
      });
      DragDrop.addhandler("dragend",function(event){
        var status = document.getElementById("status");
        status.innerHTML += "<br/> Dropped" + event.target.id + "at ("+event.x+","+event.y+")";
      });
  • 相关阅读:
    Mysql初探:内存数据刷盘机制
    数据管理流程,基础入门简介
    数据分析:复杂业务场景下,量化评估流程
    架构设计:服务自动化部署和管理流程
    Hadoop框架:MapReduce基本原理和入门案例
    架构设计:微服务模式下,实现灰度发布模式
    架构设计:分布式结构下,服务部署发布
    编码风格:Mvc模式下SSM环境,代码分层管理
    开发工具:Mybatis.Plus.插件三种方式的逆向工程
    Hadoop框架:HDFS高可用环境配置
  • 原文地址:https://www.cnblogs.com/b0xiaoli/p/3660631.html
Copyright © 2011-2022 走看看