手写封装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. 默认处理:提供兜底函数处理未匹配的情况。
相关推荐
AmyGeng1233 分钟前
el-dropdown全屏模式下不展示下拉菜单处理
javascript·vue.js·ecmascript
deckcode7 分钟前
css基础-选择器
前端·css
倔强青铜三8 分钟前
WXT浏览器开发中文教程(2)----WXT项目目录结构详解
前端·javascript·vue.js
1024小神12 分钟前
html5-qrcode前端打开摄像头扫描二维码功能
前端·html·html5
beibeibeiooo12 分钟前
【Vue3入门2】01-图片轮播示例
前端·vue.js
倔强青铜三13 分钟前
WXT浏览器开发中文教程(1)----安装WXT
前端·javascript·vue.js
2301_8153577036 分钟前
Spring:IOC
java·前端·spring
萌萌哒草头将军39 分钟前
🍍Pinia党福音,🍍Pinia伴侣:🍍pinia-colada
前端·javascript·vue.js
pe7er1 小时前
nuxtjs3使用同一个编译产物运行在多个环境中
前端·javascript
光影少年1 小时前
vue有了响应式,为何还要diff
前端·javascript·vue.js