让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 相关文章推荐
JavaScript入门教程(11) js事件处理
Jan 31 Javascript
JS 判断undefined的实现代码
Nov 26 Javascript
关于include标签导致js路径找不到的问题分析及解决
Jul 09 Javascript
Jquery增加鼠标中间功能mousewheel的实例代码
Sep 05 Javascript
jQuery实现可收缩展开的级联菜单实例代码
Nov 27 Javascript
JavaScript驾驭网页-CSS与DOM
Mar 24 Javascript
jQuery插件FusionCharts绘制的2D双柱状图效果示例【附demo源码】
May 13 jQuery
薪资那么高的Web前端必看书单
Oct 13 Javascript
jQuery实现的鼠标滚轮控制图片缩放功能实例
Oct 14 jQuery
浅谈v-for 和 v-if 并用时筛选条件方法
Nov 07 Javascript
如何通过javaScript去除字符串两端的空白字符
Feb 06 Javascript
微信小程序实现锚点跳转
Nov 23 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
PHP详解ASCII码对照表与字符转换
2011/12/05 PHP
PHP静态调用非静态方法的应用分析
2013/05/02 PHP
通过javascript设置css属性的代码
2009/12/28 Javascript
js 利用className得到对象的实现代码
2011/11/15 Javascript
使用js获取地址栏中传递的值
2013/07/02 Javascript
javascript图片延迟加载实现方法及思路
2015/12/31 Javascript
WordPress中利用AJAX异步获取评论用户头像的方法
2016/01/08 Javascript
通过jquery-ui中的sortable来实现拖拽排序的简单实例
2016/05/24 Javascript
AngularJS  $modal弹出框实例代码
2016/08/24 Javascript
基于Vuejs框架实现翻页组件
2020/06/29 Javascript
JS IOS/iPhone的Safari浏览器不兼容Javascript中的Date()问题如何解决
2016/11/11 Javascript
JavaScript实现汉字转换为拼音的库文件示例
2016/12/22 Javascript
js实现贪吃蛇小游戏(容易理解)
2017/01/22 Javascript
JS获取短信验证码倒计时的实现代码
2017/05/22 Javascript
js+html获取系统当前时间
2017/11/10 Javascript
EasyUI的DataGrid绑定Json数据源的示例代码
2017/12/16 Javascript
JS实现数组深拷贝的方法分析
2019/03/06 Javascript
countup.js实现数字动态叠加效果
2019/10/17 Javascript
vue在图片上传的时候压缩图片
2020/11/18 Vue.js
python实现的简单文本类游戏实例
2015/04/28 Python
探究Python多进程编程下线程之间变量的共享问题
2015/05/05 Python
python logging日志模块的详解
2017/10/29 Python
python导出hive数据表的schema实例代码
2018/01/22 Python
Python使用os.listdir()和os.walk()获取文件路径与文件下所有目录的方法
2019/04/01 Python
python3 property装饰器实现原理与用法示例
2019/05/15 Python
python 解决cv2绘制中文乱码问题
2019/12/23 Python
python用TensorFlow做图像识别的实现
2020/04/21 Python
Python日志打印里logging.getLogger源码分析详解
2021/01/17 Python
matplotlib bar()实现多组数据并列柱状图通用简便创建方法
2021/02/24 Python
CSS3教程(4):网页边框和网页文字阴影
2009/04/02 HTML / CSS
Watch Station官方网站:世界一流的手表和智能手表
2020/01/05 全球购物
体育专业学生自我评价范文
2014/01/17 职场文书
优秀大专毕业生求职信
2014/08/04 职场文书
2016年精神文明建设先进个人事迹材料
2016/02/29 职场文书
2016年全国助残日活动总结
2016/04/01 职场文书
vue中使用mockjs配置和使用方式
2022/04/06 Vue.js