手写封装JS函数重载功能

在 JavaScript 中,函数本身不支持传统面向对象语言(如 Java)的**重载(Overload)**机制,但可以通过 参数判断高阶函数 模拟实现函数重载。以下是手写封装函数重载的两种实现方式:


方法一:基于参数类型和数量的动态分发

通过闭包收集多个重载函数,调用时根据参数匹配最合适的实现。

javascript 复制代码
/**
 * 创建支持重载的函数
 * @param {object} [obj] 可选,绑定重载方法的对象(用于对象方法重载)
 * @returns {Function} 可添加重载逻辑的函数
 */
function createOverload(obj) {
  const overloadedFns = new Map(); // 存储重载函数:key=参数特征, value=函数

  // 重载注册方法:为特定参数模式注册函数
  function overload(...args) {
    const key = args.map(arg => {
      // 参数类型判断:'number', 'string', 'boolean', 'object', 'function', 'array' 等
      if (Array.isArray(arg)) return 'array';
      if (arg === null) return 'null';
      if (arg === undefined) return 'undefined';
      return typeof arg;
    }).join(',');

    return function(targetFn) {
      overloadedFns.set(key, targetFn);
      return overload; // 链式调用
    };
  }

  // 实际执行的函数
  function execute(...args) {
    const key = args.map(arg => {
      if (Array.isArray(arg)) return 'array';
      if (arg === null) return 'null';
      if (arg === undefined) return 'undefined';
      return typeof arg;
    }).join(',');

    const fn = overloadedFns.get(key);
    if (!fn) throw new Error(`No overload found for parameters: ${key}`);
    
    // 绑定对象上下文(如 obj.method() 调用)
    return fn.apply(obj || this, args);
  }

  execute.overload = overload;
  return execute;
}

使用示例

javascript 复制代码
// 创建重载函数
const getData = createOverload();

// 注册不同参数模式的重载
getData.overload('string')(function(name) {
  return `Fetching data by name: ${name}`;
});

getData.overload('number')(function(id) {
  return `Fetching data by ID: ${id}`;
});

getData.overload('string', 'number')(function(name, priority) {
  return `Fetching data by name (${name}) with priority ${priority}`;
});

// 测试调用
console.log(getData('Alice'));        // "Fetching data by name: Alice"
console.log(getData(123));            // "Fetching data by ID: 123"
console.log(getData('Bob', 5));       // "Fetching data by name (Bob) with priority 5"

方法二:基于参数长度和类型的优先级匹配

更复杂的实现,支持参数长度和类型的组合匹配,并处理默认情况。

javascript 复制代码
class Overload {
  constructor() {
    this.overloads = [];
  }

  /**
   * 添加重载函数
   * @param {Function} fn 目标函数
   * @param {Function[]} checkers 参数校验函数数组
   * @returns {Overload} 支持链式调用
   */
  add(fn, checkers) {
    this.overloads.push({ fn, checkers });
    return this;
  }

  /**
   * 执行匹配的重载函数
   * @param {...any} args 调用参数
   * @returns {any} 重载函数的返回值
   */
  execute(...args) {
    // 按注册顺序倒序查找,后添加的优先级更高
    for (let i = this.overloads.length - 1; i >= 0; i--) {
      const { fn, checkers } = this.overloads[i];
      if (args.length !== checkers.length) continue;

      const match = checkers.every((check, index) => {
        const arg = args[index];
        return check(arg);
      });

      if (match) {
        return fn.apply(this, args);
      }
    }

    throw new Error('No matching overload found.');
  }
}

使用示例

javascript 复制代码
const search = new Overload();

// 重载 1:按字符串搜索
search.add(
  (query) => `Search by string: ${query}`,
  [arg => typeof arg === 'string']
);

// 重载 2:按数字 ID 和布尔标志搜索
search.add(
  (id, flag) => `Search by ID: ${id} (flag: ${flag})`,
  [arg => typeof arg === 'number', arg => typeof arg === 'boolean']
);

// 重载 3:默认情况(无匹配时)
search.add(
  (...args) => `Fallback search with args: ${args.join(', ')}`,
  [] // 空校验器,始终匹配
);

// 测试调用
console.log(search.execute('test'));     // "Search by string: test"
console.log(search.execute(123, true)); // "Search by ID: 123 (flag: true)"
console.log(search.execute({}, 456));   // "Fallback search with args: [object Object], 456"

关键实现思路

步骤 说明
收集重载函数 存储不同参数模式对应的函数实现
参数特征提取 将参数类型、数量转换为唯一标识(如 'string,number'
匹配优先级 按注册顺序或参数复杂度确定匹配优先级(如参数数量多的优先)
执行匹配函数 遍历重载集合,找到第一个匹配项并执行

应用场景

  1. API 封装:根据不同参数类型调用不同底层方法。
  2. 工具函数 :如 $() 根据参数类型返回 DOM 元素或创建新元素。
  3. 数据处理:根据输入格式(数组、对象、字符串)选择处理逻辑。

注意事项

  1. 性能优化:避免过多重载层级,复杂场景建议用策略模式。
  2. 类型检查 :精确校验参数类型(如区分 arrayobject)。
  3. 默认处理:提供兜底函数处理未匹配的情况。
相关推荐
LuciferHuang7 小时前
震惊!三万star开源项目竟有致命Bug?
前端·javascript·debug
GISer_Jing7 小时前
前端实习总结——案例与大纲
前端·javascript
天天进步20157 小时前
前端工程化:Webpack从入门到精通
前端·webpack·node.js
姑苏洛言8 小时前
编写产品需求文档:黄历日历小程序
前端·javascript·后端
知识分享小能手9 小时前
Vue3 学习教程,从入门到精通,使用 VSCode 开发 Vue3 的详细指南(3)
前端·javascript·vue.js·学习·前端框架·vue·vue3
姑苏洛言9 小时前
搭建一款结合传统黄历功能的日历小程序
前端·javascript·后端
hackchen9 小时前
Go与JS无缝协作:Goja引擎实战之错误处理最佳实践
开发语言·javascript·golang
你的人类朋友10 小时前
🤔什么时候用BFF架构?
前端·javascript·后端
知识分享小能手10 小时前
Bootstrap 5学习教程,从入门到精通,Bootstrap 5 表单验证语法知识点及案例代码(34)
前端·javascript·学习·typescript·bootstrap·html·css3