JavaScript不支持重载的语法,它没有重载所需要的函数签名。

ECMAScript函数不能像传统意义上那样实现重载。而在其他语言(如 Java)中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。如前所述,ECMAScirpt函数没有签名,因为其参数是由包含零或多个值的数组来表示的。而没有函数签名,真正的重载是不可能做到的。 — JavaScript高级程序设计(第3版)3.7.2小节

而且在JavaScript中,函数名本身就是变量,函数声明类似于变量赋值。当同个函数名被多次声明时,后声明的内容将覆盖前面的内容,如下所示:

function addSomeNumber(num){return num + 100;
}
function addSomeNumber(num){return num + 200;
}
var result = addSomeNumber(100); // => 300

尽管JavaScript无法做到真正的重载,但是可以通过检查传入函数中参数的类型和数量并作相应的处理,从而实现重载的效果,曲线救国。 下面介绍几种JS重载的姿势:

姿势一:借助流程控制语句

通过判断传入参数的数量(arguments.length),执行相应的代码块。

function doSomething(){switch(arguments.length){case 0:/* 代码块 */break;...case n:/* 代码块 */break;}
}

姿势二:巧用闭包特性

jQuery创始人John Resig在《Secrets of the JavaScript Ninja》的第4.4.2小节中介绍了一种方法,如下所示,可通过addMethod函数将对象ninja的whatever方法进行重载。

var ninja = {};
addMethod(ninja, 'whatever', function(){/* code */});
addMethod(ninja, 'whatever', function(a){/* code */});
addMethod(ninja, 'whatever', function(a,b){/* code */});

addMethod函数接收3个参数:目标对象、目标方法名、函数体,当函数被调用时:
1. 先将目标object[name]的值存入变量old中,因此起初old中的值可能不是一个函数
2. 接着向object[name]赋值一个代理函数,并且由于变量old、fn在代理函数中被引用,所以old、fn将常驻内存不被回收。

function addMethod(object, name, fn) {var old = object[name];  // 保存前一个值,以便后续调用object[name] = function(){  // 向object[name]赋值一个代理函数// 判断fn期望接收的参数与传入参数个数是否一致if (fn.length == arguments.length)// 若是,则调用fnreturn fn.apply(this, arguments)else if (typeof old == 'function')  // 若否,则判断old的值是否为函数// 若是,则调用oldreturn old.apply(this, arguments);};
}

代理函数被调用时:
1. 先判断传入参数与其父级作用域中fn期望接收参数的个数是否一致,若是则调用该fn;
2. 若否,则判断其父级作用域中old值类型是否为函数,若是则调用该old;
3. 当old中存有上一次生成的代理函数时,则会重复前面两个步骤,直至old值不为代理函数


上述两种方法都是通过检查参数个数来实现重载,不区分参数类型
此外,方法1在继承时重载的那些函数无法被重写,而方法2通过逐个执行代理函数,比对参数个数,直至找到目标函数,效率不高。
为了解决这些问题,我构思设计一个方法,见下文。若你知道更好的方法或思路,还请留言指点一下。


姿势三:巧用引用类型特性

核心思想:由于ECMAScript函数是一种引用类型对象,可扩展属性与方法。借此通过创建一个容器用于存储要重载的函数,并将容器挂载到代理函数上以便后续访问,而代理函数利用闭包特性访问容器。
重载顺序:首先查找参数类型匹配的函数,其次查找参数个数匹配的函数。
存储格式:键值对,键名由逗号与参数个数或参数类型组成,键值为要重载的函数,如下:

{',0': function(){/* code */},',1': function(a){/* code */},',string,number': function(a,b){/* code */}
}

工具函数被调用时
1. 先判断是否已重载过,若有,直接将要重载的函数按格式存入容器;
2. 若未重载过,则创建一个容器变量;
3. 判断未重载前的值是否为一个函数,若是,则以逗号+参数个数的格式存入容器;
4. 将要重载的函数存入容器;
5. 代理原函数,并将容器挂载到代理函数上;
6. 当代理函数被调用时,将依次查找容器中匹配的函数并调用。

/*** 重载工具函数* @param {Object} ctx - 上下文* @param {String} name - 函数名* @param {Function} fn - 函数体* @param {String} type - 参数类型* @author 范围兄 <ambit_tsai@qq.com>* @example 不指定参数类型*  overload(obj, 'do', function(){...});*  overload(obj, 'do', function(a){...});* @example 指定参数类型*  overload(obj, 'do', function(a,b){...}, 'string,number');*/
function overload(ctx, name, fn, type){type = type? type.trim().toLowerCase(): fn.length;// 已重载过if(typeof ctx[name]==='function' && typeof ctx[name]._$fnMap==='object'){ctx[name]._$fnMap[','+type] = fn;   // 将fn存入_$fnMapreturn;}// 未重载过var fnMap = {};   // 容器if(typeof ctx[name] === 'function'){// 若ctx[name]是一个函数,则存入容器fnMap[','+ctx[name].length] = ctx[name];}fnMap[','+type] = fn;ctx[name] = function overloading(){   // 代理var args = arguments, len = args.length, type, i;for(i=0, type=''; i<len; ++i){  // 计算参数类型type += ',' + typeof args[i];}// 依次匹配:参数类型->参数个数if(fnMap[type]) return fnMap[type].apply(this, args);if(fnMap[','+len]) return fnMap[','+len].apply(this, args);throw 'Overload: no matched function';};ctx[name]._$fnMap = fnMap;   // 将fnMap挂载到代理上
}

都看到这了,给点个赞呗 (。◕∀◕。)

JS方法/函数重载的姿势相关推荐

  1. Js 方法函数记录笔记

    系统方法函数 // 编码:encodeURI("张童瑶") // 结果:"%E5%BC%A0%E7%AB%A5%E7%91%B6"// 解码:decodeURI ...

  2. 利用Javascript的“函数重载”实现自定义Alert样式

    默认的Alert只有一个简单的对话框,而且无法自定义样式!有时候弹出的提示需要很详尽,并且显得有些冗长,那么如何让用户直接看到重点信息呢?因为系统自带的Alert无法编辑样式所以我们只好自己重新定义一 ...

  3. 美丽的闭包,在js中实现函数重载

    引言 最近在js的学习中,看到了函数重载的问题,一开始,只看到了实现代码,看着代码冥思苦想了半个小时,总算是理清了其实现的原理,也为其实现的巧妙感到赞叹,也是在自己搞懂原理之后,去网络上搜索了下,才知 ...

  4. JS函数重载解决方案

    JS的函数定义可以指定形式参数名称,多多少少我们会以为js至少可以支持参数个数不同的方法重载,然而遗憾的是这仅仅是一个假象,js所有的参数都是以arguments传递过去的,这个参数类似于数组,在函数 ...

  5. js中函数参数arguments、callee、caller,值传递、重载

    全栈工程师开发手册 (作者:栾鹏) js系列教程4-函数.函数参数教程全解 函数参数 arguments javascript中的函数定义并未指定函数形参的类型,函数调用也未对传入的实参值做任何类型检 ...

  6. php是否直接支持函数的重载,php函数重载的替代方法--伪重载详解

    对于弱类型语言来说,PHP函数重载,并不像一般的OOP那样.而弱类型本来就不区分,所以无法通过这些来实现.但是,可以通过下面的方法来实现简单的伪重载吧. 函数重载的替代方法-伪重载,下面看一个具体的实 ...

  7. js Date 函数方法

    转载自   js Date 函数方法 var myDate = new Date();myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取 ...

  8. Java方法01 方法(函数)定义、调用、值传递、重载、命令行传递参数

    Java 方法的定义.调用.值传递.重载.命令行传递参数 1. 什么是方法? 2. 方法的定义和调用 3. 值传递和引用传递 4. 方法的重载 5. 命令行传递参数 6. 可变参数(输入参数的数量不确 ...

  9. js数据类型 方法 函数

    Js数据类型具体分析 1.     基础类型:  string  number   boolean   null  undefined 2.     引用类型:  object ==>  jso ...

最新文章

  1. 一起学WPF系列(2):第一个WPF应用程序
  2. 【SpringCloud】Zuul-实例
  3. 【转】【Android】使用BaseAdapter实现复杂的ListView
  4. decode函数吗 jsp_JSP中js传递和解析URL参数以及中文转码和解码问题
  5. php表格之间设置间隔,html表格如何设置间距
  6. 两个时间的差值Java,Java如何找到两个时间之间的差值?
  7. Java String substring()方法示例
  8. 微信“小程序 未完, 数据的小程序 又来了
  9. 金蝶KIS/K3各版本下载地址
  10. 用envi裁剪下来的图像是黑色的_ENVI进行图像裁剪.doc
  11. python物性库能调用哪些物质_Python 调用 CoolProp 计算介质的物性
  12. 如何恢复计算机永久删除文件,怎么恢复被彻底删除的文件?简单有效方法分享...
  13. 【IDEA双击快捷方式无法打开】
  14. 触动精灵 - 获取颜色相似度
  15. 建立centos6的yum源服务器
  16. 网页版在线使用PS网站源码
  17. 傅立叶变换的物理意义(转)
  18. WEB安全 TCP协议安全 应用安全 信息安全 业务安全 SDK嵌入式防护 等保 攻击溯源 CDN DCDN
  19. 协同过滤入门介绍(转)
  20. 企业级计算机储存容量,家用NAS与企业级NAS功能大比拼

热门文章

  1. VMware Workstations Pro 14 建立的虚拟机目录无法删除
  2. Sublime Text 3 -mac版简体中文汉化教程
  3. 基于javaweb小说评价下载网站管理系统 ssm框架
  4. 数论基础,从入门到入门
  5. mysql关联删除(删除不存在另一张表的记录)
  6. 数据库的主键约束、唯一约束、外键约束
  7. “互联网寒冬”来袭,软件测试人员该如何度过这次危机?
  8. 浮点数打印其实是个复杂的过程
  9. DHD的上网设置与彩信设置
  10. 美剧推荐:abc新剧Traveler