让JavaScript 轻松支持函数重载 (Part 1 - 设计)


Posted in Javascript onAugust 04, 2009

JavaScript支持重载吗?
JavaScript支持函数重载吗?可以说不支持,也可以说支持。说不支持,是因为JavaScript不能好像其它原生支持函数重载的语言一样,直接写多个同名函数,让编译器来判断某个调用对应的是哪一个重载。说支持,是因为JavaScript函数对参数列表不作任何限制,可以在函数内部模拟对函数重载的支持。
实际上,在很多著名的开源库当中,我们都可以看到函数内部模拟重载支持的设计。例如说jQuery的jQuery.extend方法,就是通过参数类型判断出可选参数是否存在,如果不存在的话就对参数进行移位以确保后面的逻辑正确运行。我相信很多人在写JavaScript时也写过类似的代码,以求为功能丰富的函数提供一个(或多个)简单的调用入口。
不过做种做法一个根本的问题,那就是违反了DRY原则。每个支持重载的函数内部都多出来一段代码,用于根据参数个数和参数类型处理重载,这些代码暗含着重复的逻辑,写出来却又每一段都不一样。此外,这些代码要维护起来也不容易,因为阅读代码时你并不能一眼看出函数支持的几种重载方式是什么,要对重载做出维护自然也困难。
描述重载入口的DSL
我希望能够在JavaScript中以一种简单的方式来描述重载入口。最好就如同在其它语言中一样,使用函数签名来区分重载入口,因为我认为函数签名就是这方面最好的DSL。我假想中最符合JavaScript语法的重载入口描述DSL应该是这样子的:

var sum = new Overload(); 
sum.add("Number, Number", 
function(x, y) { return x + y; }); 
sum.add("Number, Number, Number", 
function(x, y, z) { return x + y + z; });

在描述好重载入口与对应函数体后,对sum函数的调用应该是这样子的:
sum(1, 2);
sum(1, 2, 3);
上述代码在我看来非常清晰,也非常容易维护——你可以一眼看得出重载入口的签名,并且要修改或者增加重载入口都是很容易的事情。但是我们遇到了一个问题,那就是JavaScript里面的函数是不能new出来的,通过new Overload()获得的对象一定不能被调用,为此我们只能把Overload做成一个静态类,静态方法返回的是Function实例:
var sum = Overload 
.add("Number, Number", 
function(x, y) { return x + y; }) 
.add("Number, Number, Number", 
function(x, y, z) { return x + y + z; });

必要的重载入口支持
想象一下,有哪些常见的JavaScript函数入口是用上述DSL无法描述的?我所知道的有两种:
任意类型参数
假想我们要写一个each函数,对于Array就迭代它的下标,对于其它类型就迭代它的所有成员,这两个函数入口的参数列表如何声明?如果用C#,我们会如此描述两个函数入口:
void Each(IEnumerable iterator) { }
void Each(object iterator) { }
然而在JavaScript当中,Object不是一切类型的基类,(100) instanceof Object的结果为false,所以我们不能用Object来指代任意类型,必须引入一个新的符号来指代任意类型。考虑到这个符号不应该与任何可能存在的类名冲突,所以我选择了用"*"来表示任意类型。上述C#代码对应的JavaScript应该是这样子的:
var each = Overload 
.add("Array", 
function(array) { }) 
.add("*", 
function(object) { });

任意数量参数
在JavaScript的函数里面,要求支持任意数量参数是很常见的需求,相信使用率比C#里面的params关键字要多得多。在我们之前制定的规则当中,这也无法描述的,因此我们要引入一个不和类名冲突的符号来表示C#中的params。我选择了用"..."表示params,意思是这里出现任意多个参数都是可以接受的。让我们看看jQuery.extend的重载应该如何描述:
var extend = Overload 
.add("*, ...", 
function(target) { }) 
.add("Boolean, *, ...", 
function(deep, target) { });

小结
在这篇文章当中,我们尝试设计出一种适用于JavaScript且易读易维护的函数重载写法。在下一篇文章当中,我们将会尝试编写Overload类,以实现这一设计。
Javascript 相关文章推荐
TinyMCE 新增本地图片上传功能
Nov 05 Javascript
使用javascript实现ListBox左右全选,单选,多选,全请
Nov 07 Javascript
jQuery实现的背景动态变化导航菜单效果
Aug 24 Javascript
jQuery基于muipicker实现仿ios时间选择
Feb 22 Javascript
jQuery select自动选中功能实现方法分析
Nov 28 Javascript
Bootstrap Table使用整理(二)
Jun 09 Javascript
vue单页开发父子组件传值思路详解
May 18 Javascript
React 源码中的依赖注入方法
Nov 07 Javascript
vue cli3.0 引入eslint 结合vscode使用
May 27 Javascript
简单了解JavaScript中常见的反模式
Jun 21 Javascript
jQuery三组基本动画与自定义动画操作实例总结
May 09 jQuery
JS中箭头函数与this的写法和理解
Jan 14 Javascript
JavaScript 异步调用框架 (Part 6 - 实例 & 模式)
Aug 04 #Javascript
javascript 支持链式调用的异步调用框架Async.Operation
Aug 04 #Javascript
JavaScript 异步调用框架 (Part 5 - 链式实现)
Aug 04 #Javascript
JavaScript 异步调用框架 (Part 4 - 链式调用)
Aug 04 #Javascript
JavaScript 异步调用框架 (Part 3 - 代码实现)
Aug 04 #Javascript
JavaScript 异步调用框架 (Part 2 - 用例设计)
Aug 03 #Javascript
JavaScript 异步调用框架 (Part 1 - 问题 & 场景)
Aug 03 #Javascript
You might like
《神奇女侠:血脉》神力女超人大战犯罪公司
2020/04/09 欧美动漫
关于laravel 子查询 & join的使用
2019/10/16 PHP
判断js中各种数据的类型方法之typeof与0bject.prototype.toString讲解
2013/11/07 Javascript
js 验证身份证信息有效性
2014/03/28 Javascript
学习javascript面向对象 理解javascript原型和原型链
2016/01/04 Javascript
浅析JavaScript 箭头函数 generator Date JSON
2016/05/23 Javascript
下一代Bootstrap的5个特点 超酷炫!
2016/06/17 Javascript
Jquery实现遮罩层的简单实例(就是弹出DIV周围都灰色不能操作)
2016/07/14 Javascript
AngularJS国际化详解及示例代码
2016/08/18 Javascript
浅析JavaScript的几种Math函数,random(),ceil(),round(),floor()
2016/12/22 Javascript
如何提高Dom访问速度
2017/01/05 Javascript
jsonp跨域请求实现示例
2017/03/13 Javascript
jQuery中hover方法搭配css的hover选择器,实现选中元素突出显示方法
2017/05/08 jQuery
JS实现倒序输出的几种常用方法示例
2019/04/13 Javascript
Electron-vue开发的客户端支付收款工具的实现
2019/05/24 Javascript
Vue.js 中的实用工具方法【推荐】
2019/07/04 Javascript
layui中的switch开关实现方法
2019/09/03 Javascript
[48:29]2018DOTA2亚洲邀请赛3月30日 小组赛A组 LGD VS KG
2018/03/31 DOTA
[57:41]Secret vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
结合Python的SimpleHTTPServer源码来解析socket通信
2016/06/27 Python
Python图形绘制操作之正弦曲线实现方法分析
2017/12/25 Python
基于pandas将类别属性转化为数值属性的方法
2018/07/25 Python
selenium+python设置爬虫代理IP的方法
2018/11/29 Python
python代码实现逻辑回归logistic原理
2019/08/07 Python
python os.path.isfile()因参数问题判断错误的解决
2019/11/29 Python
详解python 支持向量机(SVM)算法
2020/09/18 Python
Python爬虫过程解析之多线程获取小米应用商店数据
2020/11/14 Python
Servlet如何得到客户端机器的信息
2014/10/17 面试题
网络编辑岗位职责范本
2014/02/10 职场文书
2014年幼儿园重阳节活动方案
2014/09/16 职场文书
先进党支部事迹材料
2014/12/24 职场文书
2015年暑期社会实践总结
2015/07/13 职场文书
2016暑期师德培训心得体会
2016/01/09 职场文书
创业计划书之餐饮
2019/09/02 职场文书
MATLAB 如何求取离散点的曲率最大值
2021/04/16 Python
Java实现添加条码或二维码到Word文档
2022/06/01 Java/Android