对于javascript函数重载这个概念,参考书籍上多多少少都会提及,也就是从语言角度来说,javascript不支持函数重载,不能够定义同样的函数然后通过编译器去根据不同的参数执行不同的函数。
但是javascript却可以通过自身属性去模拟函数重载。
书上常见的比较无意义的例子,比如一个计算器函数,如果参数为两个数字,就执行加法运算。如果参数为三个数字,就执行乘法运算
这个函数大家最容易想到的实现就是
function calculate() { if (arguments.length == 2) { return arguments[0] + arguments[1]; } if (arguments.length == 3) { return arguments[0] * arguments[1] * arguments[2]; } } alert(calculate(1, 3))
这个函数看起来没什么不好,但随着需求的增多,if分支就会越来越庞大,而且对应的模式也越来越难看。虽然if对于语言来说没啥不好。但我们可以考虑使用另一个策略来实现这个需求。
这就是一个新的函数重载模式。代码如下
var map = function (arr, callback, pThis) { var len = arr.length; var rlt = new Array(len); for (var i = 0; i < len; i++) { if (i in arr) rlt[i] = callback.call(pThis, arr[i], i, arr); } return rlt; } /** * 函数参数重载方法 overload,对函数参数进行模式匹配。默认的dispatcher支持*和...以及?,"*"表示一个任意类型的参数,"..."表示多个任意类型的参数,"?"一般用在",?..."表示0个或任意多个参数 * @method overload * @static * @optional {dispatcher} 用来匹配参数负责派发的函数 * @param {func_maps} 根据匹配接受调用的函数列表 * @return {function} 已重载化的函数 */ var FunctionH = { overload: function (dispatcher, func_maps) { if (!(dispatcher instanceof Function)) { func_maps = dispatcher; dispatcher = function (args) { var ret = []; return map(args, function (o) { return typeof o}).join(); } } return function () { var key = dispatcher([].slice.apply(arguments)); for (var i in func_maps) { var pattern = new RegExp("^" + i.replace("*", "[^,]*").replace("...", ".*") + "$"); if (pattern.test(key)) { return func_maps[i].apply(this, arguments); } } } } };
FunctionH.overload 包括两个参数,一个是负责处理匹配条件的dispatcher函数(可缺省),另一个是一组函数映射表,默认dispatcher函数是根据实际调用的参数类型生成一个字符串,例如调用的三个参数依次为10、”a”、[1,2]将生成”number,string,array”,具体实现模式匹配的时候,将根据函数映射表的每一个”key”生成一个正则表达式,用这个正则表达式匹配dispatcher函数的返回值,如果匹配,则调用这个key对应的处理函数,否则依次匹配下一个key。这样刚才那个计算机函数的需求就可以写成为
var Calculate = FunctionH.overload({ 'number,number': function () { return arguments[0] + arguments[1]; }, 'number,number,number': function () { return arguments[0] * arguments[1] * arguments[2]; } }); alert(Calculate(1,2,3));
顺便对于浏览器兼容的代码也可以写成下面类似的形式
var MSIE = navigator.userAgent.indexOf('MSIE') !== -1; var foo = FunctionH.overload(function () { return MSIE ? "IE" : "NotIE"; }, { "IE": function () { alert('this is ie'); }, "NotIE": function () { alert('notie'); } }); foo();
评论前必须登录!
注册