在 JavaScript 中,函数本身不支持传统面向对象语言(如 Java)的**重载(Overload)**机制,但可以通过 参数判断 和 高阶函数 模拟实现函数重载。以下是手写封装函数重载的两种实现方式:
方法一:基于参数类型和数量的动态分发
通过闭包收集多个重载函数,调用时根据参数匹配最合适的实现。
javascript
/**
* 创建支持重载的函数
* @param {object} [obj] 可选,绑定重载方法的对象(用于对象方法重载)
* @returns {Function} 可添加重载逻辑的函数
*/
function createOverload(obj) {
const overloadedFns = new Map(); // 存储重载函数:key=参数特征, value=函数
// 重载注册方法:为特定参数模式注册函数
function overload(...args) {
const key = args.map(arg => {
// 参数类型判断:'number', 'string', 'boolean', 'object', 'function', 'array' 等
if (Array.isArray(arg)) return 'array';
if (arg === null) return 'null';
if (arg === undefined) return 'undefined';
return typeof arg;
}).join(',');
return function(targetFn) {
overloadedFns.set(key, targetFn);
return overload; // 链式调用
};
}
// 实际执行的函数
function execute(...args) {
const key = args.map(arg => {
if (Array.isArray(arg)) return 'array';
if (arg === null) return 'null';
if (arg === undefined) return 'undefined';
return typeof arg;
}).join(',');
const fn = overloadedFns.get(key);
if (!fn) throw new Error(`No overload found for parameters: ${key}`);
// 绑定对象上下文(如 obj.method() 调用)
return fn.apply(obj || this, args);
}
execute.overload = overload;
return execute;
}
使用示例
javascript
// 创建重载函数
const getData = createOverload();
// 注册不同参数模式的重载
getData.overload('string')(function(name) {
return `Fetching data by name: ${name}`;
});
getData.overload('number')(function(id) {
return `Fetching data by ID: ${id}`;
});
getData.overload('string', 'number')(function(name, priority) {
return `Fetching data by name (${name}) with priority ${priority}`;
});
// 测试调用
console.log(getData('Alice')); // "Fetching data by name: Alice"
console.log(getData(123)); // "Fetching data by ID: 123"
console.log(getData('Bob', 5)); // "Fetching data by name (Bob) with priority 5"
方法二:基于参数长度和类型的优先级匹配
更复杂的实现,支持参数长度和类型的组合匹配,并处理默认情况。
javascript
class Overload {
constructor() {
this.overloads = [];
}
/**
* 添加重载函数
* @param {Function} fn 目标函数
* @param {Function[]} checkers 参数校验函数数组
* @returns {Overload} 支持链式调用
*/
add(fn, checkers) {
this.overloads.push({ fn, checkers });
return this;
}
/**
* 执行匹配的重载函数
* @param {...any} args 调用参数
* @returns {any} 重载函数的返回值
*/
execute(...args) {
// 按注册顺序倒序查找,后添加的优先级更高
for (let i = this.overloads.length - 1; i >= 0; i--) {
const { fn, checkers } = this.overloads[i];
if (args.length !== checkers.length) continue;
const match = checkers.every((check, index) => {
const arg = args[index];
return check(arg);
});
if (match) {
return fn.apply(this, args);
}
}
throw new Error('No matching overload found.');
}
}
使用示例
javascript
const search = new Overload();
// 重载 1:按字符串搜索
search.add(
(query) => `Search by string: ${query}`,
[arg => typeof arg === 'string']
);
// 重载 2:按数字 ID 和布尔标志搜索
search.add(
(id, flag) => `Search by ID: ${id} (flag: ${flag})`,
[arg => typeof arg === 'number', arg => typeof arg === 'boolean']
);
// 重载 3:默认情况(无匹配时)
search.add(
(...args) => `Fallback search with args: ${args.join(', ')}`,
[] // 空校验器,始终匹配
);
// 测试调用
console.log(search.execute('test')); // "Search by string: test"
console.log(search.execute(123, true)); // "Search by ID: 123 (flag: true)"
console.log(search.execute({}, 456)); // "Fallback search with args: [object Object], 456"
关键实现思路
步骤 | 说明 |
---|---|
收集重载函数 | 存储不同参数模式对应的函数实现 |
参数特征提取 | 将参数类型、数量转换为唯一标识(如 'string,number' ) |
匹配优先级 | 按注册顺序或参数复杂度确定匹配优先级(如参数数量多的优先) |
执行匹配函数 | 遍历重载集合,找到第一个匹配项并执行 |
应用场景
- API 封装:根据不同参数类型调用不同底层方法。
- 工具函数 :如
$()
根据参数类型返回 DOM 元素或创建新元素。 - 数据处理:根据输入格式(数组、对象、字符串)选择处理逻辑。
注意事项
- 性能优化:避免过多重载层级,复杂场景建议用策略模式。
- 类型检查 :精确校验参数类型(如区分
array
和object
)。 - 默认处理:提供兜底函数处理未匹配的情况。