JS实现函数重载

函数重载

定义

函数名相同,但是参数类型或者参数个数不同的两个函数叫做函数重载。

在其他强类型语言中,函数重载是允许的,但是在JavaScript中,函数重载是不被允许的;这篇文章来记录如何实现函数重载。

场景

  1. 函数名相同

  2. 参数类型不同

  3. 参数个数不同

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的用户')
})

缺点:

  1. 必须创建一个对象,并且函数的调用顺序必须按照参数个数进行调用。

  2. 由于是根据形参数量来实现的;且形参数量受ES6默认参数的影响,会发生一些变化,此时传入参数会发现形参为0,无法匹配。

  3. 无法实现参数类型不同,但是参数个数相同的情况。

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 的用户
posted @ 2024-05-08 21:27  楚小九  阅读(158)  评论(0编辑  收藏  举报