在日常的搬砖过程中是不是经常出现下面这种类似代码,需要判断传入的参数来执行不同的逻辑,例如:
const 摸鱼代码 = (...args) => {
if(args.length === 0){
console.log(args,'默认逻辑');
return
}
if(args.length >= 1){
console.log('大于一个参数的逻辑');
}
else{
console.log('小于一个参数的逻辑');
}
};
摸鱼代码(1);
摸鱼代码();
摸鱼代码(1,2);
特别是在做一些通用库的时候用的较多,这里还只是判断参数数量来处理不同逻辑,有的还需要根据类型不同调用不同逻辑,那这段代码被下面的人接手经过长时间的业务洗礼,估计离💩不远了,一看一个不吱声
俺们先回顾下基础的重载概念:(编程技能的提升还是得多解决日常的小问题做起)
-
重载的概念
- 重载是指在一个类中定义多个同名函数,但参数列表不同(参数类型、数量或顺序不同)。
-
重载的意义:代码可读性、可维护性、灵活性
- 代码可读性: 重载可以使代码更易读,因为函数名相同,可以一目了然函数的作用,无需关注参数细节。
- 可维护性: 当需要扩展函数功能时,通过添加新的重载函数,可以避免修改已有代码,降低维护成本。
- 灵活性: 重载允许开发者根据不同的参数类型或数量调用不同的函数实现,提升代码灵活性和可扩展性。
-
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 链式调用啊 之类的 满足更多的场景,但是现在我要