JS实现函数重载
函数重载
定义
函数名相同,但是参数类型或者参数个数不同的两个函数叫做函数重载。
在其他强类型语言中,函数重载是允许的,但是在JavaScript中,函数重载是不被允许的;这篇文章来记录如何实现函数重载。
场景
-
函数名相同
-
参数类型不同
-
参数个数不同
function getUsers(...args) {
// ...
}
getUsers(); // 参数个数为0 获取所有用户
getUsers(1); // 参数个数为1 获取第一页用户,默认十个
getUsers(1, 20); // 参数个数为1 获取第一页20个用户
getUsers('张'); // 参数个数为1 获取姓张的用户
getUsers('张', '男'); // 参数个数为2 获取姓张,性别为男的用户
getUsers('张', 18); // 参数个数为2 获取姓张,年龄为18的用户
getUsers('张', '男', 18); // 参数个数为3 获取姓张,性别为男,年龄为18的用户
实现
目前有两种方案
jq实现的方案
function addMethod(obj, name, fn) {
const old = obj[name]
obj[name] = function () {
if (fn.length === arguments.length) {
return fn.apply(this, arguments)
} else if (typeof old === 'function') {
return old.apply(this, arguments)
}
}
}
const obj = {}
addMethod(obj, 'getUsers', function () {
console.log('获取所有用户')
})
addMethod(obj, 'getUsers', function (page) {
console.log('获取第一页用户,默认十个')
})
addMethod(obj, 'getUsers', function (page, size) {
console.log('获取姓张,性别为男的用户')
})
addMethod(obj, 'getUsers', function (name, gender, age) {
console.log('获取姓张,性别为男,年龄为18的用户')
})
缺点:
-
必须创建一个对象,并且函数的调用顺序必须按照参数个数进行调用。
-
由于是根据形参数量来实现的;且形参数量受ES6默认参数的影响,会发生一些变化,此时传入参数会发现形参为0,无法匹配。
-
无法实现参数类型不同,但是参数个数相同的情况。
addMethod(obj, 'getUsers', function (page = 1) { // 此时形参(args.length)数量为 0
// ...
})
根据类型实现
function createOverload() {
const fnMap = new Map()
function overload(...args) {
const key = args.map((a) => typeof a).join(',')
const fn = fnMap.get(key)
if (!fn) {
throw new Error(`未找到对应的实现`)
}
return fn.apply(this, args)
}
overload.register = function (...args) {
const fn = args.pop()
if (typeof fn !== 'function') {
throw new Error('最后一个参数必须是函数')
}
const key = args.join(',')
fnMap.set(key, fn)
}
return overload
}
// 示例
const getUsers = createOverload()
getUsers.register(() => {
console.log(`获取全部用户`)
})
getUsers.register('number', (page) => {
console.log(`获取第 ${page} 页用户`)
})
getUsers.register('number', 'number', (page, limit) => {
console.log(`获取第 ${page} 页 ${limit} 个用户`)
})
getUsers.register('string', (name) => {
console.log(`获取姓 ${name} 的用户`)
})
getUsers.register('string', 'string', (name, gender) => {
console.log(`获取姓 ${name},性别为 ${gender} 的用户`)
})
getUsers.register('string', 'number', (name, age) => {
console.log(`获取姓 ${name},年龄为 ${age} 的用户`)
})
getUsers.register('string', 'string', 'number', (name, gender, age) => {
console.log(
`获取姓 ${name},性别为 ${gender},年龄为 ${age} 的用户`
)
})
getUsers() // 获取全部用户
getUsers(1) // 获取第 1 页用户
getUsers(1, 10) // 获取第 1 页 10 个用户
getUsers('张') // 获取姓 张 的用户
getUsers('张', '男') // 获取姓 张,性别为 男 的用户
getUsers('张', 18) // 获取姓 张,年龄为 18 的用户
getUsers('张', '男', 18) // 获取姓 张,性别为 男,年龄为 18 的用户