Skip to content

函数重载

不同的参数调用,实现不同的函数操作

javaScript 并没有像一些其他编程语言(如 Java、C++)中提供显式的函数重载机制,但你可以通过一些技巧来模拟函数重载的效果

addMethod 函数重载

利用闭包、递归实现函数重载

缺点

  • 需要将函数挂载为对象属性
  • addMethod 中使用形参的长度判断,但 args.length 不计算函数参数默认值
  • 只能适配参数数量,不能适配参数类型
js
export 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, 'getArgs', () => {
  return []
})
addMethod(searcher, 'getArgs', (name) => {
  return [name]
})
addMethod(searcher, 'getArgs', (name, sex) => {
  return [name, sex]
})

searcher.getArgs()
searcher.getArgs(1)
searcher.getArgs(1, 2)
export 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, 'getArgs', () => {
  return []
})
addMethod(searcher, 'getArgs', (name) => {
  return [name]
})
addMethod(searcher, 'getArgs', (name, sex) => {
  return [name, sex]
})

searcher.getArgs()
searcher.getArgs(1)
searcher.getArgs(1, 2)

TIP

函数默认值 和 fn.length 关系

  • fn = (a, b, c) => {} fn.length === 3
  • fn = (a = 1, b, c) => {} fn.length === 0
  • fn = (a, b = 1, c) => {} fn.length === 1

createOverload 函数重载

利用闭包、hashMap 存储重载函数,解决 addMethod 缺点

  • 函数参数类型作为 key
  • 重载函数作为 value
js
export function createOverload() {
  const callMap = new Map()
  function overload(...args) {
    const key = args.map(arg => typeof arg).join(',')
    const fn = callMap.get(key)
    if (fn)
      return fn.apply(this, args)

    throw new Error('not matching function')
  }

  overload.addImpl = function (...args) {
    const fn = args.pop()
    if (typeof fn !== 'function')
      return

    const types = args
    callMap.set(types.join(','), fn)
  }
  return overload
}

// 使用
const getUsers = createOverload()

getUsers.addImpl(() => {
  console.log('查询所有用户')
})

function searchPage(page, size = 10) {
  console.log('按照页码和数量查询用户')
}

getUsers.addImpl('number', searchPage)
getUsers.addImpl('number', 'number', searchPage)

getUsers.addImpl('string', (name) => {
  console.log('按照名称查询用户')
})

getUsers.addImpl('string', 'string', (name, sex) => {
  console.log('按照名称和性别查询用户')
})

getUsers() // 查询所有用户
getUsers(10) // 按照页码和数量查询用户
getUsers(10, 20) // 按照页码和数量查询用户
getUsers('ziggy') // 按照名称查询用户
getUsers('ziggy', 'male') // 按照名称和性别查询用户
export function createOverload() {
  const callMap = new Map()
  function overload(...args) {
    const key = args.map(arg => typeof arg).join(',')
    const fn = callMap.get(key)
    if (fn)
      return fn.apply(this, args)

    throw new Error('not matching function')
  }

  overload.addImpl = function (...args) {
    const fn = args.pop()
    if (typeof fn !== 'function')
      return

    const types = args
    callMap.set(types.join(','), fn)
  }
  return overload
}

// 使用
const getUsers = createOverload()

getUsers.addImpl(() => {
  console.log('查询所有用户')
})

function searchPage(page, size = 10) {
  console.log('按照页码和数量查询用户')
}

getUsers.addImpl('number', searchPage)
getUsers.addImpl('number', 'number', searchPage)

getUsers.addImpl('string', (name) => {
  console.log('按照名称查询用户')
})

getUsers.addImpl('string', 'string', (name, sex) => {
  console.log('按照名称和性别查询用户')
})

getUsers() // 查询所有用户
getUsers(10) // 按照页码和数量查询用户
getUsers(10, 20) // 按照页码和数量查询用户
getUsers('ziggy') // 按照名称查询用户
getUsers('ziggy', 'male') // 按照名称和性别查询用户