【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 中包含之前旧的方法。这样就像洋葱一样一层一层。通过闭包访问oldfn来实现函数的重载。

当第一次调用 addMethod时,people["find"]没有定义,所以 old被赋值为 undefined(不妨记为old1),然后开始重写people["find"]不妨记为find1,以便理解。然后addMethod执行完毕,由于oldfn(记为fn1)被 people["find"]方法引用,所以活动对象仍然保留。

当第二次调用 addMethod时,people["find"]是find1,所以 old被赋值为 find1(需要注意的是这个old是一个新的局部变量,不妨记为old2),然后开始重写people["find"]不妨记为find2。然后addMethod执行完毕,由于oldfn(记为fn2)被 `people["find"]方法引用,所以活动对象仍然保留。

当第三次调用 addMethod时,people["find"]是find2,所以 old被赋值为 find2 (记为old3),然后开始重写people["find"]不妨记为find3。然后addMethod执行完毕,由于oldfn(记为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);

相信你如果对闭包有所了解,还是很容易理解上面的每一步的。

posted @   hzyuan  阅读(1713)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
点击右上角即可分享
微信分享提示