让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控件的相对独立性
Sep 06 Javascript
将HTMLCollection/NodeList/伪数组转换成数组的实现方法
Jun 20 Javascript
js网页右下角提示框实例
Oct 14 Javascript
实现placeholder效果的方案汇总
Jun 11 Javascript
JS获取中文拼音首字母并通过拼音首字母快速查找页面内对应中文内容的方法【附demo源码】
Aug 19 Javascript
基于js实现checkbox批量选中操作
Nov 22 Javascript
JS判断键盘是否按的回车键并触发指定按钮点击操作的方法
Feb 13 Javascript
vue-cli整合vuex的时候,修改actions和mutations,实现热部署的方法
Sep 19 Javascript
vue里如何主动销毁keep-alive缓存的组件
Mar 21 Javascript
vue路由跳转传参数的方法
May 06 Javascript
小程序云函数调用API接口的方法
May 17 Javascript
vue瀑布流组件实现上拉加载更多
Mar 10 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
克隆一个新项目的快捷方式
2013/04/10 PHP
Yii实现自动加载类地图的方法
2015/04/01 PHP
yii2 modal弹窗之ActiveForm ajax表单异步验证
2016/06/13 PHP
cnblogs中在闪存中屏蔽某人的实现代码
2010/11/14 Javascript
解析瀑布流布局:JS+绝对定位的实现
2013/05/08 Javascript
ExtJS判断IE浏览器类型的方法
2014/02/10 Javascript
jQuery的:parent选择器定义和用法
2014/07/01 Javascript
Javascript+CSS实现影像卷帘效果思路及代码
2014/10/20 Javascript
使用JavaScript+canvas实现图片裁剪
2015/01/30 Javascript
Node.js插件安装图文教程
2016/05/06 Javascript
jquery分隔Url的param方法(推荐)
2016/05/25 Javascript
使用plupload自定义参数实现多文件上传
2016/07/19 Javascript
基于AngularJS前端云组件最佳实践
2016/10/20 Javascript
layui前段框架日期控件使用方法详解
2017/05/19 Javascript
JS实现验证码倒计时的注册页面
2018/01/02 Javascript
vue2.0 子组件改变props值,并向父组件传值的方法
2018/03/01 Javascript
vue.js轮播图组件使用方法详解
2018/07/03 Javascript
vue中的过滤器实例代码详解
2019/06/06 Javascript
在node环境下parse Smarty模板的使用示例代码
2019/11/15 Javascript
基于Vue sessionStorage实现保留搜索框搜索内容
2020/06/01 Javascript
JS运算符优先级与表达式示例详解
2020/09/04 Javascript
vue项目实现多语言切换的思路
2020/09/17 Javascript
JavaScript实现无限轮播效果
2020/11/19 Javascript
[00:27]DOTA2战队VP、Secret贺新春
2018/02/11 DOTA
python 定时器每天就执行一次的实现代码
2019/08/14 Python
pytorch数据预处理错误的解决
2020/02/20 Python
Python opencv相机标定实现原理及步骤详解
2020/04/09 Python
sklearn中的交叉验证的实现(Cross-Validation)
2021/02/22 Python
五型班组建设方案
2014/02/10 职场文书
农村党支部书记党群众路线四风问题整改措施
2014/09/26 职场文书
大学生违纪检讨书300字
2014/10/25 职场文书
书法社团活动总结
2015/05/07 职场文书
催款函怎么写
2015/06/24 职场文书
浅谈Python numpy创建空数组的问题
2021/05/25 Python
PYTHON使用Matplotlib去实现各种条形图的绘制
2022/03/22 Python
MySQL数据库配置信息查看与修改方法详解
2022/06/25 MySQL