博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript闭包的妙用——实现函数的重载
阅读量:5752 次
发布时间:2019-06-18

本文共 3481 字,大约阅读时间需要 11 分钟。

最近在看John Resig 与 Bear Bibeault的《JavaScript 忍者秘籍》。这本书处处提现了js的魔法(从我这个写强类型语言的人看来)。js能够点石成金,处处体现着它特有的魅力。所以将一些有意思的地方记录了下来。

1.准备知识

1.1 闭包

闭包是一个函数在创建时,允许该自身函数访问并操作该自身函数以外的变量时所创建的作用域。闭包可以让函数访问所有存在于该函数声明时的作用域内的变量和函数。

innerFunction 方法能够访问到该方法调用之前的声明作用域内的变量和函数。在函数声明innerFunction的时候,同时创建了一个闭包。将函数声明这个时刻该作用域中所有的变量(参数)以及函数作用域之外的都放到了闭包中保存。

1.2 函数上下文

函数的上下文就是函数的this,调用函数的方式不同,函数的上下文不同。大致包括以下四种方式

1.2.1 作为函数调用
// 定义一个函数function ninja(){};// 对函数进行调用,ninja的this是windowninja();

通过声明函数后利用()对函数调用,那么这个函数的this就是window对象。也就是说这个函数是全局的。

1.2.2 作为方法调用
var o = {};// o对象的whatever方法作为一个匿名的函数o.whatever= function(){};// 作为方法进行调用,whatever的this就是o对象o.whatever();

将函数作为对象的方法进行调用,那么这个对象就是这个方法的上下文(this就是指的这个对象)

1.2.3 作为构造器调用
function Ninja(){    this.skulk = function(){                // 通过返回this来验证判断        return this;    }}// 通过new关键字,来使ninja()作为构造器来进行调用var ninja1 = new Ninja();var ninja2 = new Ninja();// ninja1.skulk() 返回的是ninja1 说明this 就是ninja1console.log((ninja1.skulk() === ninja1));// ninja2.skulk() 返回的是ninja2 说明this 就是ninja2console.log((ninja2.skulk() === ninja2));

通过上述的代码证明了,如果一个函数作为构造器进行调用,那么这个函数的上下文this 就是指新创建的对象,这里指的是ninja1和ninja2

1.2.4 使用apply()和call()调用

js提供apply()和call()方法,这样可以自由的为函数指定上下文。

通过apply()来调用函数,需要给apply()指定两个参数:一个是函数上下文对象,一个作为函数参数所组成的数组。
通过call()来调用函数,需要传入的参数:函数的上下文对象,函数的参数列表(call()方法的函数参数个数不一定为2

function juggle(){    var result = 0;        // 对参数进行相加    for(var n =0;n

2.基于参数个数进行重载

function addMethod(object,name,fn){   // 保存原有的函数   var old = object[name];   object[name] = function(){               // 如果该匿名函数的形参个数和实参个数匹配,就调用该函数       if(fn.length == arguments.length){           return fn.apply(this,arguments);       }else{                  // 否则就调用原来的函数           return old.apply(this,arguments);       }   }}/*****************测试代码***************************/var ninjas = {    values:["Dean Edwards","Sam Stephenson","Alex Russell"]};// 声明无参的函数addMethod(ninjas,'find',function(){    return this.values;});// 声明一个参数的函数addMethod(ninjas,'find',function(name){     var ret = [];     for(var i = 0;i < this.values.length;i++){         if(this.values[i].indexOf(name) == 0){             ret.push(this.values[i]);         }     }     return ret;});// 声明两个参数的函数addMethod(ninjas,"find",function(first,last)){    var ret = [];    for(var i = 0;i < this.values.length;i++){        if(this.values[i] == (first + " " + last)){            ret.push(this.values[i]);        }    }    return ret;}// 检测无参的方法console.log(ninjas.find().length == 3);// 检测一个参数的方法console.log(ninjas.find("Sam").length == 1);// 检测两个参数的方法console.log(ninjas.find("Dean","Edwards").length == 1);

所有的函数都有一个length属性,这个属性的值等于该函数声明时所需要传入值的数量。

该方法能够通过优雅的闭包来实现多个参数的函数重载。但是这里没有考虑到参数的类型。
addMethod()每一次的调用都会产生一个新的匿名函数。并且这个新的匿名函数通过闭包包含着一个old对象。
old方法中包含之前旧的方法。这样就像洋葱一样一层一层。通过闭包访问old和fn来实现函数的重载。

3.新功能包装旧功能的重载方式

// 定义一个包装函数,    // 接收三个参数:需要包装的方法的上下文,要包装的方法名称,需要替原有方法进行执行的方法    function wrap(object,method,wrapper){       var fn = object[method];       return object[method] = function(){                  // 通过闭包来访问fn           return wrapper.apply(this,[fn.bind(this)].concat(Array.prototype.slice.call(arguments)));           }    }//测试代码//   var o = {};      // 旧方法   o.oldFn = function(){       console.log("This is old fn");   }      // 利用wrap方法对old方法进行重载。第一个参数就是原函数   wrap(o,"oldFn",function(oldFn){       console.log("This is new fn");       oldFn();   });      // 调用   o.oldFn();

首先,原有的方法会保存在fn中。当新的方法来进行重载时。新函数执行前的包装器函数。会返回一个重新构造过得参数列表。在这个参数列表中的第一个参数就是要重载的原有函数。

转载于:https://www.cnblogs.com/MaFeng0213/p/7135909.html

你可能感兴趣的文章
FreeNAS8 ISCSI target & initiator for linux/windows
查看>>
PostgreSQL数据库集群初始化
查看>>
++重载
查看>>
Rainbond 5.0.4版本发布-做最好用的云应用操作系统
查看>>
nodejs 完成mqtt服务端
查看>>
sql server 触发器
查看>>
[工具]前端自动化工具grunt+bower+yoman
查看>>
关于完成生鲜电商项目后的一点总结
查看>>
noip2012 普及组
查看>>
第二阶段 铁大Facebook——十天冲刺(10)
查看>>
Java判断是否为垃圾_Java GC如何判断对象是否为垃圾
查看>>
多项式前k项和java_多项式朴素贝叶斯softmax改变
查看>>
java数组只能交换0下标和n_编程练习-只用0交换排序数组
查看>>
centos7安装mysql视频教程_centos7安装mysql(完整)
查看>>
php图片赋值,php如何优雅地赋值
查看>>
【探索HTML5第二弹01】HTML5的前世今生以及来世
查看>>
Failed to connect to remote VM. Connection refused. Connection refused: connect
查看>>
freeze
查看>>
SAP HANA存储过程结果视图调用
查看>>
设计模式 ( 十八 ):State状态模式 -- 行为型
查看>>