JS方法/函数重载的姿势
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方法/函数重载的姿势相关推荐
- Js 方法函数记录笔记
系统方法函数 // 编码:encodeURI("张童瑶") // 结果:"%E5%BC%A0%E7%AB%A5%E7%91%B6"// 解码:decodeURI ...
- 利用Javascript的“函数重载”实现自定义Alert样式
默认的Alert只有一个简单的对话框,而且无法自定义样式!有时候弹出的提示需要很详尽,并且显得有些冗长,那么如何让用户直接看到重点信息呢?因为系统自带的Alert无法编辑样式所以我们只好自己重新定义一 ...
- 美丽的闭包,在js中实现函数重载
引言 最近在js的学习中,看到了函数重载的问题,一开始,只看到了实现代码,看着代码冥思苦想了半个小时,总算是理清了其实现的原理,也为其实现的巧妙感到赞叹,也是在自己搞懂原理之后,去网络上搜索了下,才知 ...
- JS函数重载解决方案
JS的函数定义可以指定形式参数名称,多多少少我们会以为js至少可以支持参数个数不同的方法重载,然而遗憾的是这仅仅是一个假象,js所有的参数都是以arguments传递过去的,这个参数类似于数组,在函数 ...
- js中函数参数arguments、callee、caller,值传递、重载
全栈工程师开发手册 (作者:栾鹏) js系列教程4-函数.函数参数教程全解 函数参数 arguments javascript中的函数定义并未指定函数形参的类型,函数调用也未对传入的实参值做任何类型检 ...
- php是否直接支持函数的重载,php函数重载的替代方法--伪重载详解
对于弱类型语言来说,PHP函数重载,并不像一般的OOP那样.而弱类型本来就不区分,所以无法通过这些来实现.但是,可以通过下面的方法来实现简单的伪重载吧. 函数重载的替代方法-伪重载,下面看一个具体的实 ...
- js Date 函数方法
转载自 js Date 函数方法 var myDate = new Date();myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取 ...
- Java方法01 方法(函数)定义、调用、值传递、重载、命令行传递参数
Java 方法的定义.调用.值传递.重载.命令行传递参数 1. 什么是方法? 2. 方法的定义和调用 3. 值传递和引用传递 4. 方法的重载 5. 命令行传递参数 6. 可变参数(输入参数的数量不确 ...
- js数据类型 方法 函数
Js数据类型具体分析 1. 基础类型: string number boolean null undefined 2. 引用类型: object ==> jso ...
最新文章
- 一起学WPF系列(2):第一个WPF应用程序
- 【SpringCloud】Zuul-实例
- 【转】【Android】使用BaseAdapter实现复杂的ListView
- decode函数吗 jsp_JSP中js传递和解析URL参数以及中文转码和解码问题
- php表格之间设置间隔,html表格如何设置间距
- 两个时间的差值Java,Java如何找到两个时间之间的差值?
- Java String substring()方法示例
- 微信“小程序 未完, 数据的小程序 又来了
- 金蝶KIS/K3各版本下载地址
- 用envi裁剪下来的图像是黑色的_ENVI进行图像裁剪.doc
- python物性库能调用哪些物质_Python 调用 CoolProp 计算介质的物性
- 如何恢复计算机永久删除文件,怎么恢复被彻底删除的文件?简单有效方法分享...
- 【IDEA双击快捷方式无法打开】
- 触动精灵 - 获取颜色相似度
- 建立centos6的yum源服务器
- 网页版在线使用PS网站源码
- 傅立叶变换的物理意义(转)
- WEB安全 TCP协议安全 应用安全 信息安全 业务安全 SDK嵌入式防护 等保 攻击溯源 CDN DCDN
- 协同过滤入门介绍(转)
- 企业级计算机储存容量,家用NAS与企业级NAS功能大比拼