• jsAdvanced高级技巧


      1 /*------------ 高级函数 -------------*/
      2 //作用域安全的构造函数
      3 function Person(name, age, job) {
      4     this.name = name;
      5     this.age = age;
      6     this.job = job;
      7 }
      8 var person = new Person("Nicholas", 29, "Software Engineer");
      9 console.log(person.name);   //Nicholas
     10 console.log(person.age);    //29
     11 /*当没有使用new操作符来调用构造函数时,由于该this对象是在运行是绑定的,所以直接调用Person(),this会映射到全局对象window上,导致错误对象属性的意外增加。由于window内置了name属性,因此很有可能出错*/
     12 var person1 = Person("Nicholas", 29, "Software Engineer");  //作为普通函数调用,将属性添加到window对象中
     13 console.log(window.name);   //Nicholas
     14 console.log(window.age);    //29
     15 console.log(window.job);    //Software Engineer
     16 
     17 //解决:首先确认this对象是正确类型的实例,如果不是,会创建新的实例并返回
     18 function Person(name, age, job) {
     19     if (this instanceof Person) {
     20         this.name = name;
     21         this.age = age;
     22         this.job = job;
     23     } else {
     24         return new Person(name, age, job);
     25     }
     26 }
     27 var person1 = Person("Nicholas", 29, "Software Engineer");
     28 console.log(window.name);   //""
     29 console.log(person1.name);  //Nicholas
     30 var person2 = new Person("Shelly", 34, "Teacher");
     31 console.log(person2.name);  //Shelly
     32 
     33 //关于作用与安全的构造函数注意:
     34 //如果你是用构造函数窃取模式的继承且不使用原型链,那么这个继承很可能被破坏
     35 function Polygon(sides) {
     36     if (this instanceof Polygon) {
     37         this.sides = sides;
     38         this.getArea = function () {
     39             return 0;
     40         };
     41     } else {
     42         return new Polygon(sides);
     43     }
     44 }
     45 function Rectangle(width, height) {
     46     Polygon.call(this, 2);
     47     this.width = width;
     48     this.height = height;
     49     this.getarea = function () {
     50         return this.width * this.height;
     51     };
     52 }
     53 var rect = new Rectangle(5, 10);
     54 console.log(rect.sides);    //undefined
     55 
     56 //使用原型链或寄生组合解决这个问题
     57 function Polygon(sides) {
     58     if (this instanceof Polygon) {
     59         this.sides = sides;
     60         this.getArea = function () {
     61             return 0;
     62         };
     63     } else {
     64         return new Polygon(sides);
     65     }
     66 }
     67 function Rectangle(width, height) {
     68     Polygon.call(this, 2);
     69     this.width = width;
     70     this.height = height;
     71     this.getArea = function () {
     72         return this.width * this.height;
     73     };
     74 }
     75 //继承Polygon,一个Rectangle实例,同时也是一个Polygon实例
     76 Rectangle.prototype = new Polygon();
     77 var rect = new Rectangle(5, 10);
     78 console.log(rect.sides);    //2
     79 
     80 
     81 //惰性载入函数
     82 function createXHR() {
     83     if (typeof XMLHttpRequest !== "undefined") {
     84         return new XMLHttpRequest();
     85     } else if (typeof ActiveXObject !== "undefined") {
     86         if (typeof arguments.callee.activeXString !== "string") {
     87             var version = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"];
     88             for (var i = 0, len = versions.length; i < len; i++) {
     89                 try {
     90                     var xhr = new ActiveXObject(versions[i]);
     91                     arguments.callee.activeXString = versions[i];
     92                     return xhr;
     93                 } catch (ex) {
     94                     //跳过
     95                 }
     96             }
     97         }
     98         return new ActiveXObject(arguments.callee.activeXString);
     99     } else {
    100         throw new Error("No XHR object available");
    101     }
    102 }
    103 /*每次调用createXHR()的时候,它都要对浏览器所支持的能力仔细检查,即使每次调用时分支的结果都不变。*/
    104 //解决方法:惰性载入技巧
    105 //表示函数执行的分支仅会发生一次,在第一次调用的过程中,该函数会被覆盖为另外一个按合适方式执行的函数
    106 function createXHR() {
    107     if (typeof XMLHttpRequest !== "undefined") {
    108         createXHR = function () {
    109             return new XMLHttpRequest();
    110         };
    111     } else if (typeof ActiveXObject !== "undefined") {
    112         createXHR = function () {
    113             if (typeof arguments.callee.activeXString !== "string") {
    114                 var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"];
    115                 for (var i = 0, len = versions.length; i < len; i++) {
    116                     try {
    117                         var xhr = new ActiveXObject(versions[i]);
    118                         arguments.callee.activeXString = versions[i];
    119                         return xhr;
    120                     } catch (ex) {
    121 
    122                     }
    123                 }
    124             }
    125             return new ActiveXObject(arguments.callee.activeXString);
    126         };
    127     } else {
    128         createXHR = function () {
    129             throw new Error("No XHR object available");
    130         };
    131     }
    132     return createXHR();     //调用新赋的函数
    133 }
    134 
    135 //函数绑定
    136 //函数绑定要创建一个函数,可以在特定环境中以指定参数调用另一个函数
    137 //该技巧长航和回调函数与事件处理程序一起使用,以便将函数作为变量传递的同时保留代码执行环境
    138 var handler = {
    139     message:"Event handled",
    140     handlerClick:function (event) {
    141         alert(this.message);
    142     }
    143 };
    144 var btn = document.getElementById("my-btn'");
    145 EventUtil.addHandler(btn, "click", handler.handlerClick);     //undefined, this指向了btn
    146 //解决:使用闭包保存函数的环境
    147 var handler = {
    148     message:"Event handled",
    149     handlerClick:function (event) {
    150         alert(this.message);
    151     }
    152 };
    153 var btn = document.getElementById("my-btn'");
    154 EventUtil.addHandler(btn, "click", function (event) {
    155     handler.handlerClick(event);            //Event handled, 内部闭包函数切断了this对外部的指向,保留了执行环境
    156 });
    157 
    158 /**
    159  * 将函数绑定到指定环境的函数
    160  * @param fn 函数
    161  * @param context 环境
    162  * @return {Function}
    163  */
    164 function bind(fn, context) {
    165     return function () {
    166         return fn.apply(context, arguments);
    167     };
    168 }
    169 /*
    170  在bind()中创建了一个闭包,闭包使用apply()调用传入函数,并给apply()传递context对象和参数。注意这里使用的arguments对象是内部函数的,而非bind()的。当调用返回的函数时,它会在给定环境中执行被传入的函数并给出所有参数。bind()函数按如下方式使用:
    171  */
    172 var handler = {
    173     message:"Event handled",
    174     handlerClick:function (event) {
    175         alert(this.message);
    176     }
    177 };
    178 var btn = document.getElementById("my-btn'");
    179 EventUtil.addHandler(btn, "click", bind(handler.handlerClick, handler));
    180 /*
    181  旦要将某个函数指针以值的形式进行传递,同时该函数必须在特定环境中执行,被绑定函数的效用就凸显出来了。它们主要用于事情处理程序以及setTimeout()和setInterval()。然而,被绑定函数与普通函数相比有更多的开销——它们需要更多的内存,同时也因为多重函数调用稍微慢一点——所以最好只在必要时使用。
    182  */
    183 
    184 
    185 //函数柯里花
    186 //用于创建已经设置好了一个或多个参数的函数
    187 /*
    188  函数柯里花的基本方法和函数绑定是一样的,使用一个闭包返回一个函数。
    189  两者区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数
    190  */
    191 function add(num1, num2) {
    192     return num1 + num2;
    193 }
    194 function curriedAdd(num2) {
    195     return add(5, num2);
    196 }
    197 console.log(add(2, 3));  //5
    198 console.log(curriedAdd(3)); //8
    199 //尽管并非柯里化的函数,但它很好的展示其概念
    200 
    201 //创建柯里花函数的通用方式:
    202 function curry(fn) {
    203     /*
    204      将外部函数参数转换成数组,并获取第一个参数之后的所有参数(不包括第一个,因为第一个是函数)
    205      */
    206     var args = Array.prototype.slice.call(arguments, 1);
    207     return function () {
    208         //获取所有内部函数参数
    209         var innerArgs = Array.prototype.slice.call(arguments);
    210         //外部参数和内部参数组合
    211         var finalArgs = args.concat(innerArgs);
    212         //返回fn函数,并将最后的参数传入
    213         return fn.apply(null, finalArgs);
    214     };
    215 }
    216 
    217 //example:
    218 function add(num1, num2) {
    219     return num1 + num2;
    220 }
    221 var curriedAdd = curry(add, 5);
    222 console.log(curriedAdd(3)); //8
    223 //或者
    224 function add(num1, num2) {
    225     return num1 + num2;
    226 }
    227 var curriedAdd = curry(add, 5, 12);
    228 console.log(curriedAdd());      //17
    229 
    230 //更为复杂的bind()函数
    231 function bind(fn, context) {
    232     //获取外部函数第二个之后的所有参数的数组
    233     var args = Array.prototype.slice.call(arguments, 2);
    234     return function () {
    235         //获取内部fn函数的所有参数
    236         var innerArgs = Array.prototype.slice.call(arguments);
    237         //外部参数+内部参数
    238         var finalArgs = args.concat(innerArgs);
    239         //返回fn函数,并传入最后的所有参数,执行环境指向context
    240         return fn.apply(context, finalArgs);
    241     };
    242 }
    243 
    244 var handler = {
    245     message:"Event handled",
    246     handleClick:function (name, event) {
    247         alert(this.message + ":" + name + ":" + event.type);
    248     }
    249 };
    250 var btn = document.getElementById("my-btn");
    251 EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler, "my-btn"));   //Event handled:my-btn:click
    252 //柯里化函数和绑定函数提供了强大的动态函数创建功能,但不该滥用,会带来额外开销
    253 
    254 
    255 /****************  自定义事件*******************/
    256 /**
    257  * 绑定函数和柯里化函数
    258  * @param fn 执行的函数
    259  * @param context 绑定的环境
    260  * @return {Function} 返回带参数的函数
    261  */
    262 function bind(fn, context) {
    263     //获取外部函数第二个之后的所有参数的数组
    264     var args = Array.prototype.slice.call(arguments, 2);
    265     return function () {
    266         //获取内部fn函数的所有参数
    267         var innerArgs = Array.prototype.slice.call(arguments);
    268         //外部参数+内部参数
    269         var finalArgs = args.concat(innerArgs);
    270         //返回fn函数,并传入最后的所有参数,执行环境指向context
    271         return fn.apply(context, finalArgs);
    272     };
    273 }
    274 
    275 //对非DOM元素实现自定义事件
    276 function EventTarget() {
    277     //存储事件处理程序的属性对象
    278     this.handlers = {};
    279 }
    280 EventTarget.prototype = {
    281     //重新将constructor指向EventTarget构造函数
    282     constructor:EventTarget,
    283     /**
    284      * 注册给定类型时间的事件处理程序
    285      * @param type 自定义的事件类型
    286      * @param handler 处理该事件类型的函数
    287      */
    288     addHandler:function (type, handler) {
    289         //如果handlers属性中没有存在一个针对该事件类型的数组
    290         //则创建一个新的。(一个事件类型可以对应多个事件处理函数,因此要用数组保存)
    291         //然后使用push()将该处理程序添加到数组的末尾
    292         if (typeof this.handlers[type] === "undefined") {
    293             this.handlers[type] = [];
    294         }
    295         this.handlers[type].push(handler);
    296     },
    297     /**
    298      * 触发事件
    299      * @param event 一个至少包含type属性的对象
    300      */
    301     fire:function (event) {
    302         //给event对象设置一个target属性
    303         if (!event.target) {
    304             event.target = this;
    305         }
    306         //如果该事件类型的执行函数存在,
    307         //调用各个函数,并给出event对象
    308         if (this.handlers[event.type] instanceof Array) {
    309             var handlers = this.handlers[event.type];
    310             for (var i = 0, len = handlers.length; i < len; i++) {
    311                 handlers[i](event);
    312             }
    313         }
    314     },
    315     /**
    316      * 注销事件类型的事件处理程序
    317      * @param type 事件类型
    318      * @param handler 执行的函数
    319      */
    320     removeHandler:function (type, handler) {
    321         if (this.handlers[type] instanceof Array) {
    322             var handlers = this.handlers[type];
    323             //搜索事件处理程序的数组找到要删除的处理程序的位置
    324             //找到了就退出循环,然后将该项目丛数组中删除
    325             for (var i = 0, len = handlers.length; i < len; i++) {
    326                 if (handlers[i] === handler) {
    327                     break;
    328                 }
    329             }
    330             handlers.splice(i, 1);
    331         }
    332     }
    333 };
    334 //创建一个新对象
    335 var target = new EventTarget();
    336 //添加一个事件处理程序
    337 target.addHandler("message", handlerMessage);
    338 //触发事件
    339 target.fire({
    340     type:"message",
    341     message:"Hello world"
    342 }); //Message received:Hello world
    343 
    344 //删除事件处理程序
    345 target.removeHandler("message", handlerMessage);
    346 //再次,应没有处理程序
    347 target.fire({
    348     type:"message",
    349     message:"Hello world"
    350 });
    351 
    352 //其他对象可以继承EvntTarget并获取这个行为
    353 function Person(name, age) {
    354     //继承属性
    355     EventTarget.call(this);
    356     this.name = name;
    357     this.age = age;
    358 }
    359 //浅复制
    360 function object(o) {
    361     function F() {
    362     }
    363 
    364     F.prototype = o;
    365     return new F();
    366 }
    367 function inheritPrototype(subType, superType) {
    368     var prototype = object(superType.prototype);      //创建对象
    369     prototype.constructor = subType;      //增强对象
    370     subType.prototype = prototype;        //指定对象
    371 }
    372 //继承原型中的方法
    373 inheritPrototype(Person, EventTarget);
    374 Person.prototype.say = function (message) {
    375     this.fire({
    376         type:"message",
    377         message:message
    378     });
    379 }
    380 
    381 function handleMessage(event) {
    382     alert(event.target.name + " says:" + event.message);
    383 }
    384 //创建新person
    385 var personN = new Person("NIcholas", 29);
    386 //添加一个事件处理程序
    387 personN.addHandler("message", handleMessage);
    388 //在该对象上调用1个方法,触发消息事件
    389 personN.say("Hi there");
    390 
    391 //拖放
    392 var DragDrop = function () {
    393     var dragging = null;
    394 
    395     function handleEvent(event) {
    396         //获取事件和目标
    397         event = EventUtil.getTarget(event);
    398         var target = EventUtil.getTarget(event);
    399 
    400         //确定事件类型
    401         switch (event.type) {
    402             case "mousedown":
    403                 if (target.className.indexOf("draggable") > -1) {
    404                     dragging = target;
    405                 }
    406                 break;
    407             case "mousemove":
    408                 if (dragging !== null) {
    409                     //get event
    410                     event = EventUtil.getEvent(event);
    411                     //assign location
    412                     dragging.style.left = event.clientX + "px";
    413                     dragging.style.top = event.clientY + "px";
    414                 }
    415                 break;
    416             case "mouseup":
    417                 dragging = null;
    418                 break;
    419         }
    420     }
    421 
    422     //公公接口
    423     return {
    424         enable:function () {
    425             EventUtil.addHandler(document, "mousedown", handleEvent);
    426             EventUtil.addHandler(document, "mousemove", handleEvent);
    427             EventUtil.addHandler(document, "mouseup", handlerEvent);
    428         },
    429         disable:function () {
    430             EventUtil.removeHandler(document, "mousedown", handleEvent);
    431             EventUtil.removeHandler(document, "mousemove", handleEvent);
    432             EventUtil.removeHandler(document, "mouseup", handlerEvent);
    433         }
    434     };
    435 }();
  • 相关阅读:
    hibernate 字段名最好不要使用数据库的保留字
    Tomcat Java内存溢出 PermGen space 解决方案
    jsp关于include html、jsp等文件出现乱码问题的解决方案
    hibernate annotation注解 columnDefinition用法
    hibernate annotation注解 主键ID自增长
    Java将整个文件夹里的文本中的字符串替换成另外一个字符串(可用于项目复制,变成另一个项目)
    FreeMarker 乱码解决方案 生成静态html文件
    Java发送post请求
    编程式导航
    vue-router 的重定向-redirect
  • 原文地址:https://www.cnblogs.com/webFrontDev/p/2786029.html
Copyright © 2020-2023  润新知