【JavaScript】JS 中实现方法重载
方法重载是根据形参的数量、类型不同而调用相应的同名方法。
JavaScript 方法本身是不存在方法重载的,后一个方法会覆盖前面的同名方法:
function fun() {
return 1;
}
function fun(param) {
return 2;
}
fun(); //2
fun(0); //2
JavaScript 中实现函数重载,主要有两种途径(没有考虑到参数的类型):
- 利用arguments类数组来判断实参个数
- 利用闭包保存之前注册进来的同名函数
通过arguments实现
arguments.length
可以获得实参的数量,函数名.length
可以获取形参的数量。
这里我们可以实现通过实参的数量不同来实现不同的处理。
function fun() {
if(arguments.length == 0) {
return 1;
} else if(arguments.length == 1) {
return 2;
}
}
fun(); //1
fun(0); //2
闭包实现方法重载
闭包是指有权访问另一个函数作用域变量的函数,创建闭包的通常方式,是在一个函数内部创建另一个函数。
想深入了解闭包可以看这篇文章,讲得很好。
先来个网上很容易搜到的闭包实现方法重载的例子
function addMethod (object, name, fn) {
// 把前一次添加的方法存在一个临时变量old中
var old = object[name];
// 重写object[name]方法
object[name] = function () {
if (fn.length === arguments.length) {
// 若是调用object[name]方法时,若是实参和形参个数一致,则直接调用
return fn.apply(this, arguments);
} else if (typeof old === 'function') {
// 若是实参形参不一致,判断old是不是函数,若是,就调用old
return old.apply(this, arguments);
}
};
}
var people = {
values: ['Dean Edwards', 'Sam Stephenson', 'Alex Russell', 'Dean Tom']
};
//find all values
addMethod(people, 'find', function() {
return this.values;
});
//find value by fisrtName
addMethod(people, 'find', function(firstName) {
return this.values.filter((value) => {
return value.indexOf(firstName) !== -1 ? true : false;
});
});
//find value by firstName and lastName
addMethod(people, 'find', function(firstName, lastName) {
return this.values.filter((value) => {
var fullName = `${firstName} ${lastName}`;
return value.indexOf(fullName) !== -1 ? true : false;
});
});
console.log(people.find()); // ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"]
console.log(people.find('Dean')); // ["Dean Edwards", "Dean Tom"]
console.log(people.find('Dean', 'Edwards')); // ["Dean Edwards"]
现在来深入解析下这个例子,方便理解闭包如何实现方法重载。
可以看到 addMethod
方法被调用了三次,每一次调用都会产生一个新的匿名函数,并且这个新的匿名函数通过闭包包含着一个 old
变量和fn
函数。
addMethod
方法在每次执行时,都会生成一个 addMethod
的活动变量和执行环境,执行完毕以后完后都只是销毁了执行环境,但活动对象由于被闭包函数所引用,仍然保留。old
中包含之前旧的方法。这样就像洋葱一样一层一层。通过闭包访问old
和fn
来实现函数的重载。
当第一次调用 addMethod
时,people["find"]
没有定义,所以 old
被赋值为 undefined(不妨记为old1),然后开始重写people["find"]
,不妨记为find1,以便理解。然后addMethod
执行完毕,由于old
和 fn
(记为fn1)被 people["find"]
方法引用,所以活动对象仍然保留。
当第二次调用 addMethod
时,people["find"]
是find1,所以 old
被赋值为 find1(需要注意的是这个old是一个新的局部变量,不妨记为old2),然后开始重写people["find"]
,不妨记为find2。然后addMethod
执行完毕,由于old
和 fn
(记为fn2)被 `people["find"]方法引用,所以活动对象仍然保留。
当第三次调用 addMethod
时,people["find"]
是find2,所以 old
被赋值为 find2 (记为old3),然后开始重写people["find"]
,不妨记为find3。然后addMethod
执行完毕,由于old
和 fn
(记为fn3)被 `people["find"]方法引用,所以活动对象仍然保留。
当我们调用 people.find()
时,由于此时的 people.find
是 find3,实参个数为0,fn3的形参个数为2,两者个数不等,所以 执行old.apply(this, arguments);
。这个 old
是 old3,值是find2。
find2 中 fn2 的形参个数为 1,也不同,所以执行old.apply(this, arguments);
这个 old
是 old2,值是find1。
find1 中 fn1 的形参个数为 0,实参和形参个数相同,所以执行fn.apply(this, arguments);
相信你如果对闭包有所了解,还是很容易理解上面的每一步的。
本文来自博客园,作者:hzyuan,转载请注明原文链接:https://www.cnblogs.com/hzyuan/p/15873311.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)