# 概念
函数重载是指在编程语言中允许定义多个同名函数,但是他们的参数类型、参数个数或者返回类型不同,编译器或解析器会根据调用时提供的参数类型和个数来确定使用哪个函数
# 作用
函数重载的主要目的就是提高代码的可读性和灵活性,同时避免了为不同功能编写不同的函数名导致的变量命名冲突和混乱。
# 实现函数重载
# ts
ts 中进行函数重载其实就是根据型参数组的个数和对变量进行 typeof 检测,然后根据不同的情况进行分支处理
// 函数重载的声明 | |
function average(numbers: number[]): number; // 函数签名 1:接受数字数组并返回数字 | |
function average(...numbers: number[]): number; // 函数签名 2:接受可变数量的数字参数并返回数字 | |
// 函数实现 | |
function average(...args: any[]): number { // 实际函数实现 | |
let sum = 0; | |
if (args.length === 1 && Array.isArray(args[0])) { // 如果传入的是数组 | |
const numbers = args[0] as number[]; // 类型断言为数字数组 | |
for (const num of numbers) { | |
sum += num; | |
} | |
return sum / numbers.length; | |
} else if (args.length > 1) { // 如果传入的是多个数字 | |
for (const num of args) { | |
sum += num; | |
} | |
return sum / args.length; | |
} else { | |
throw new Error('Invalid arguments'); // 抛出错误,不支持的参数类型 | |
} | |
} | |
// 调用函数重载 | |
console.log(average([1, 2, 3, 4, 5])); // 输出: 3 | |
console.log(average(1, 2, 3, 4, 5)); // 输出: 3 |
# js
js 中也可以通过 typeof 和形参数组进行函数重载,不过当然还有更好的做法,jQuery 作者常用如下实现函数重载(进行重载之前要调用一次函数):
function addMethod(object,name,fn){ | |
const old = object[name]; | |
object[name] = function (...args){ | |
if(args.length === fn.length){ | |
return fn.apply(this,args); | |
}else if(typeof old === 'function'){ | |
return old.apply(this,args); | |
} | |
} | |
}; | |
const searcher = {}; // 将对象中对应属性的重载方法全部存储起来 | |
addMethod(searcher,'getUsers',()=>{ | |
console.log('查询所有用户'); | |
}); | |
addMethod(searcher,'getUsers',(name='a')=>{ // 注意默认参数的形参数量不与计数 | |
console.log('按照姓名查询用户'); | |
}); | |
searcher.getUsers(); |
另一种实现方法就是使用映射:
function createOverload(){ | |
const fnMap = new Map(); | |
function overload(...args){ | |
const key = args.map((it) => typeof it).join(','); | |
const fn = fnMap.get(key); | |
if(!fn){ | |
throw new TypeError('没有找到对应的实现'); | |
} | |
return fn.apply(this,args); | |
} | |
overload.addImpl = function(...args){ | |
const fn = args.pop(); | |
if(typeof fn !== 'function'){ | |
throw new TypeError('最后一个参数必须是函数') | |
} | |
const key = args.join(','); | |
fnMap.set(key,fn); | |
}; | |
return overload; | |
} | |
const getUsers = createOverload(); | |
getUsers.addImpl(()=>{ | |
console.log('查询所有用户'); | |
}); | |
getUsers.addImpl('number',(page,size=10)=>{ | |
console.log('按照页码和数量查询用户'); | |
}); | |
getUsers.addImpl('number','number',(page,size=10)=>{ | |
console.log('按照页码和数量查询用户'); | |
}) | |
getUsers.addImpl('string',(name)=>{ | |
console.log('按照姓名查询用户'); | |
}); | |
getUsers.addImpl('string','string',()=>{ | |
console.log('按照性别查询用户'); | |
}); | |
getUsers('asfsdf'); |
总结一下实现思路,通过 createOverload 函数调用可以返回一个重载后的函数,createOverload 函数中创建了一个 map,map 中将参数类型和个数与对应的函数相匹配,返回的重载函数在调用时会根据参数的类型去 map 中寻找对应的函数,通过 apply 绑定 this 作用域和参数执行即可。