咱这样解决JS函数重载

546 阅读3分钟

在日常的搬砖过程中是不是经常出现下面这种类似代码,需要判断传入的参数来执行不同的逻辑,例如:

const 摸鱼代码 = (...args) => {

   if(args.length === 0){
       console.log(args,'默认逻辑');
       return 
   }

   if(args.length >= 1){
       console.log('大于一个参数的逻辑');
   }
   else{
      console.log('小于一个参数的逻辑');
   }

};

摸鱼代码(1);
摸鱼代码();
摸鱼代码(1,2);

特别是在做一些通用库的时候用的较多,这里还只是判断参数数量来处理不同逻辑,有的还需要根据类型不同调用不同逻辑,那这段代码被下面的人接手经过长时间的业务洗礼,估计离💩不远了,一看一个不吱声

太优秀的程序员普遍单身 (2).gif

俺们先回顾下基础的重载概念:(编程技能的提升还是得多解决日常的小问题做起)

  • 重载的概念

    • 重载是指在一个类中定义多个同名函数,但参数列表不同(参数类型、数量或顺序不同)。
  • 重载的意义:代码可读性、可维护性、灵活性

    • 代码可读性:  重载可以使代码更易读,因为函数名相同,可以一目了然函数的作用,无需关注参数细节。
    • 可维护性:  当需要扩展函数功能时,通过添加新的重载函数,可以避免修改已有代码,降低维护成本。
    • 灵活性:  重载允许开发者根据不同的参数类型或数量调用不同的函数实现,提升代码灵活性和可扩展性。
  • JavaScript 缺乏真正意义上的重载机制

    • JavaScript 没有像 Java 或 C++ 那样提供真正的函数重载机制,因为 JavaScript 解释器会根据函数名和参数列表的组合进行匹配,而不是在编译时进行重载解析。

解决方案1


const reloadMethod = (object,name,callback) => {
    const old = object[name];
    object[name] = (...args) => {
       if(args.length === callback.length){
           return callback.apply(this,args);
       }else if (typeof callback === 'function'){
           return old.apply(this,args);
       }
    }
}

const obj ={}

reloadMethod(obj,'test',()=>{
    console.log('0个参数');
})

reloadMethod(obj,'test',(arg1)=>{
    console.log('一个参数');
})

reloadMethod(obj,'test',(arg1,arg2)=>{
    console.log('二个参数');
})


优点:

  • 使用简单,易于理解。
  • 可以模拟函数重载,根据不同参数数量调用不同的函数。

缺点:

  • 代码可读性可能较差,尤其是当重载的函数比较多的时候。
  • 无法通过类型检查来区分不同的函数。
  • 不支持默认参数的写法 如下:
const reloadMethod = (object,name,callback) => {
    const old = object[name];
    object[name] = (...args) => {
        console.log(callback.length,'参数长度') //0
       if(args.length === callback.length){
           return callback.apply(this,args);
       }else if (typeof callback === 'function'){
           return old.apply(this,args);
       }
    }
}

const obj ={}


reloadMethod(obj,'test',(arg1=2)=>{
    console.log('一个参数',arg1);
})

obj.test(1)

callback.length的长度是排除掉了默认参数的,所以不匹配,这种封装问题比较多,所以我们来看第二种

解决方案2

我们想一下,我们的使用方式是怎么样的:

  • 支持添加函数
  • 支持参数的类型不同调用
a.add(types,fn) // 大概的调用方式

a() // 根据types的不同 执行不同回调,跟上面那种使用基本差不多
a(1)

那么 a 如何来呢?

a.add如何来呢

所以我们的目的就实现一个a 和 a.add 这个方法就行,大家可以思考一下,我这里给出一个参考方案

const reloadMethod = () => {
  const mapParams = new Map();
  function overload(...args) {
    const paramsKeys = args.map((param) => typeof param).join(",");
    const callback = mapParams.get(paramsKeys);
    if (typeof callback === "function") {
      return callback.apply(this, args);
    } else {
      throw new Error("没有找到匹配的方法");
    }
  }
  overload.add = (...args) => {
    const callback = args.pop(); // 拿到最后一个回调
    const params = args;
    mapParams.set(params.join(","), callback);
    if (typeof callback !== "function") {
      throw new Error("callback must be a function");
    }
  };

  return overload;
};

思路也比较简单,利用map来存储params的唯一性,然后取出回调执行,这里注意 overload 不能用箭头函数,避免this出现错误

进行测试一下,也支持默认传参的方式

const test = reloadMethod();

test.add("number", "number", (page, pageSize = 1) => {
  console.log("有参数", page,pageSize);
});


test.add("number", (page, pageSize = 1) => {
    console.log("有参数", page,pageSize);
});

test(1, 2);
test(1);

在做深一些 可以封装成hooks 链式调用啊 之类的 满足更多的场景,但是现在我要

Suggestion (2).gif