JavaScript 函数重载实现:基于模式匹配的 dispatcher 机制
本文介绍如何在 JavaScript 中通过 FunctionH.overload 实现函数重载。利用自定义 dispatcher 函数生成参数特征字符串,结合通配符(*、...、?)构建正则表达式进行模式匹配,从而根据参数类型和数量动态分发执行不同逻辑,提升代码兼容性与优雅度。
引言:优雅兼容与函数重载
infinte 同学提出的“更优雅的兼容”方案,实际上与本文探讨的技术路径存在关联,后续内容将对此展开说明。
FunctionH.overload 机制详解
在 youa 脚本库的 Function Helper 模块中,新增了对函数重载功能的支持,核心机制基于模式匹配。
具体实现代码如下:
/**
函数参数重载方法 overload 用于对函数参数进行模式匹配。默认的 dispatcher 支持 *、... 以及 ? 三种通配符:* 代表任意单个类型的参数,... 代表任意数量的参数,? 通常用于可选参数场景(如 ,?... 表示 0 个或多个参数)。
* @method overload
* @static
* @optional {dispatcher} 负责匹配参数并执行分发的函数
* @param {func_maps} 根据匹配结果调用的函数映射表
* @return {function} 完成重载处理的函数
*/
overload: function(dispatcher, func_maps) {
if (! (dispatcher instanceof Function)) {
func_maps = dispatcher;
dispatcher = function(args) {
var ret = [];
return map(args, function(o) {return getType(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);
}
}
};
}, 默认 Dispatcher 与模式匹配原理
FunctionH.overload 接收两个参数:一个是可选的 dispatcher 函数,负责处理匹配条件;另一个是函数映射表。若未提供 dispatcher,系统使用默认实现,该实现根据调用时的实际参数类型生成字符串(例如参数为 10、”a”、[1,2] 时生成 ”number,string,array”)。在模式匹配阶段,系统会将映射表中的每个 key 转换为正则表达式,并与 dispatcher 返回的字符串进行比对。若匹配成功,则执行对应 key 的处理函数;否则继续尝试下一个 key。
具体代码示例如下:
getEx: function(obj, prop, returnJson) {
var ret, propType = ObjectH.getType(prop);
if (propType == 'array') {
if (returnJson) {
ret = {};
for (var i = 0; i & lt; prop.length; i++) {
ret[prop[i]] = ObjectH.getEx(obj, prop[i]);
}
} else {
//getEx(obj, props)
ret = [];
for (var i = 0; i & lt; prop.length; i++) {
ret[i] = ObjectH.getEx(obj, prop[i]);
}
}
} else {
//getEx(obj, prop)
var keys = (prop + "").split(".");
ret = obj;
for (var i = 0; i & lt; keys.length; i++) {
ret = ret[keys[i]];
}
if (returnJson) {
var json = {};
json[prop] = ret;
return json;
}
}
return ret;
}, 基于通配符的模式匹配示例
针对上述代码中繁琐的 if-else 判断,可以通过重载机制进行优化:
优化后的代码如下:
getEx: FunctionH.overload({
"*,array,*": function(obj, prop, returnJson) {
if (returnJson) {
ret = {};
for (var i = 0; i & lt; prop.length; i++) {
ret[prop[i]] = ObjectH.getEx(obj, prop[i]);
}
} else {
ret = [];
for (var i = 0; i & lt; prop.length; i++) {
ret[i] = ObjectH.getEx(obj, prop[i]);
}
}
return ret;
},
"*,string,*": function(obj, prop, returnJson) {
var keys = (prop + "").split(".");
ret = obj;
for (var i = 0; i & lt; keys.length; i++) {
ret = ret[keys[i]];
}
if (returnJson) {
var json = {};
json[prop] = ret;
return json;
}
return ret;
}
}), 自定义 Dispatcher 实现精准分发
这种写法在部分开发者眼中可能已优于原始版本,但仍有进一步简化的空间——
改进后的代码如下:
getEx: FunctionH.overload(function(args) {
return "prop is " + ObjectH.getType(args[1]);
},{
"prop is array": function(obj, prop, returnJson) {
if (returnJson) {
ret = {};
for (var i = 0; i & lt; prop.length; i++) {
ret[prop[i]] = ObjectH.getEx(obj, prop[i]);
}
} else {
//getEx(obj, props)
ret = [];
for (var i = 0; i & lt; prop.length; i++) {
ret[i] = ObjectH.getEx(obj, prop[i]);
}
}
return ret;
},
"prop is string": function(obj, prop, returnJson) {
var keys = (prop + "").split(".");
ret = obj;
for (var i = 0; i & lt; keys.length; i++) {
ret = ret[keys[i]];
}
if (returnJson) {
var json = {};
json[prop] = ret;
return json;
}
return ret;
}
}), 多参数组合匹配与特性探测应用
此外,对于令人困扰的第三个参数,也可以一并纳入处理逻辑——
完整处理代码如下:
getEx: FunctionH.overload(function(args) {
return "prop is " + ObjectH.getType(args[1]) + " and returnJson is " +args[2];
},{
"prop is array and returnJson is true": function(obj, prop, returnJson) {
ret = {};
for (var i = 0; i & lt; prop.length; i++) {
ret[prop[i]] = ObjectH.getEx(obj, prop[i]);
}
return ret;
},
"prop is array and returnJson is false": function(obj, prop, returnJson) {
ret = [];
for (var i = 0; i & lt; prop.length; i++) {
ret[i] = ObjectH.getEx(obj, prop[i]);
}
return ret;
},
"prop is string and returnJson is true": function(obj, prop, returnJson) {
var keys = (prop + "").split(".");
ret = obj;
for (var i = 0; i & lt; keys.length; i++) {
ret = ret[keys[i]];
}
var json = {};
json[prop] = ret;
return json;
},
"prop is string and returnJson is false": function(obj, prop, returnJson) {
var keys = (prop + "").split(".");
ret = obj;
for (var i = 0; i & lt; keys.length; i++) {
ret = ret[keys[i]];
}
return ret;
}
}), 类似浏览器嗅探或特性探测等场景,同样可以应用此模式(需注意该方式利弊并存,使用者应自行权衡)——
示例代码如下:
foo = FunctionH.overload(function() {
return MSIE ? "IE": "NotIE";
},{
"IE": function() {...}
"NotIE": function() {...}
}); JS合并多个数组的三种方法:concat、spread与flat
2026-11-05 17:39:45
JavaScript怎么准确判断数据类型:typeof、instanceof与Object.prototype.toString
2026-11-05 17:09:21
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
