JS 函数重载

JS 函数重载

简介

函数重载简单来说就是一个函数多个用途,可以根据参数的不同执行不同的结果。

比如说定义一个 查询信息的函数 getInfo(),用于查询数据。

// 默认所有
queryInfo()
// 查询第一个
queryInfo(1)
// 查询第一个 张字开头
queryInfo(1, "张")
// 张字开头 男性
queryInfo("张", "男")

以上就是简单的函数重载示例,而在 JS 中,没有真正意义上的函数重载。
这是因为 JS 是动态类型语言,参数类型可变,原本定义的是字符串,传数字传对象都行。参数长度也可变,只接受一个参数的函数, 传十个参数也行。而且后面定义的函数会覆盖前面的函数。

function example (arg = 0) {
  console.log("参数")
}
function example (arg = "") {
  console.log("zfc")
}

example(0)
example("23")
example({})
example(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

但是有没有办法去实现呢?有的。

JS 实现函数重载

在 JS 所有非箭头函数中,都有一个内置局部对象 arguments,通过它可以获得一个参数集合。
如果使用了 ES6 语法,可以通过剩余参数语法来获取 这个是可以用在箭头函数上的。

function queryInfo (args) {
    // do somethings...
    console.log(arguments)
}
queryInfo(3, 3, "张")
// 获取的 arguments: [Arguments] { "0": 3, "1": 3, "2": "张" }

const queryInfo = (...args) => {
    // do somethings...
    console.log(args)
}
queryInfo(3,3,"张")
// 获取的 args: [ 3, 3, "张" ]

因此 可以通过 arguments 或 剩余参数进行实现函数重载。

// 剩余参数
// function queryInfo (...args) {
// arguments
function queryInfo () {
    const args = arguments
    if (args.length === 0) // 默认情况
    else if (args.length === 1) {
        if (typeof args[0] === "string") // 查询开头为 xx 的
        else if (typeof args[0] === "number") // 查询第 n 个
    }
    // ...
}

有点复杂,可以改成这样。

const queryInfo = function (...args) {
  // 使用对象保存数据
  const options = {}
  // 一个个的获取参数
  for (const arg of args) {
    // 如果参数是数字
    if (typeof arg === "number") {
      // 如果序列不存在则赋予它
      if (options.order === undefined) options.order = arg
      // 否则如果偏移不存在则赋予它
      else if (options.offset === undefined) options.offset = arg
    // 如果是字符串
    } else if (typeof arg === "string") {
      // 如果开头字符不存在则赋予
      if (options.firstChar === undefined) options.firstChar = arg
      // 如果性别不存在则赋予
      else if (options.sex === undefined) options.sex = arg
    }
  }
  let result = "查询"
  if (JSON.stringify(options) !== "{}") {
    if (options.order) result += `第${options.order}个`
    if (options.offset) result += `偏移${options.offset}页`
    if (options.firstChar) result += `开头为${options.firstChar}`
    if (options.sex) result += `性别为${options.sex}`
  } else result += "所有"
  result += "的数据"
  console.log(result)
}

// 默认所有
queryInfo()
// 查询第一个
queryInfo(1)
// 查询第一个 张字开头
queryInfo(1, "张")
// 查询第一个 张字开头 男性
queryInfo(1, "张", "男")
// 查询第一个 偏移三页
queryInfo(1, 3)
// 查询第三个 偏移三页 张字开头
queryInfo(3, 3, "张")
// 查询开头为张
queryInfo("张")
// 查询开头为张 性别男
queryInfo("张", "男")
// 查询开头为张 第一个
queryInfo("张", 1)

以上示例为根据参数类型等的函数重载,如果是简单的根据参数数量进行的话可以参考以下。

/**
 * 使用了闭包的重载方法
 * @param { object } object 绑定方法对象
 * @param { string } name 绑定方法名称
 * @param { function } fn 重载函数
 */
function addMethod (object, name, fn) {
  const old = object[name]; // 把前一次添加的方法存在一个临时变量old里面
  object[name] = function () { // 重写了object[name]的方法
    // 如果调用object[name]方法时,传入的参数个数跟预期的一致,则直接调用
    if (fn.length === arguments.length) {
        return fn.apply(this, arguments);
        // 否则,判断old是否是函数,如果是,就调用old
    } else if (typeof old === "function") {
        return old.apply(this, arguments);
    }
  }
}

const obj = {}
addMethod(obj, "test", () => 0)
addMethod(obj, "test", (first) => 1)
addMethod(obj, "test", (first, second) => 2)
addMethod(obj, "test", (first, second, third) => 3)

以上代码,当执行 obj.test() 时,首先执行的是最后一个传入的函数,(first,second,third) => 3的判断部分。

参数数量不对,调用 old。 old 为第三次传入的 (first,second) => 2 的判断。参数数量也不对,则一直重复下去直到匹配到或没有重载的函数了。

简单来说就是一个链表。从最后一个节点直到第一个节点。

TS 实现函数重载

首先需要先声明函数的重载。声明完毕之后,函数的逻辑需要手动的去实现。

// index.d.ts
declare function overload (): string[]
declare function overload (firstChar: string): string[]
declare function overload (firstChar: string, lessThan: number): boolean
declare function overload (order: number): string

然后是实现。

function overload (firstChar: string | number, lessThan?: number) {
  const result: string[] = []
  if (lessThan) return false
  if (typeof firstChar === "number") return ""
  return result
}

JS 函数重载
http://localhost:8080/archives/5af15c43-dd0a-4839-a17d-e00a0f8885ea
作者
inksha
发布于
2024年09月14日
许可协议