【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);

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

推荐这些技术文章:

前端 JS 问题记录

立即执行函数 !function(){}()
function 前面增加符号 ! ~ + - 之类,都是告诉浏览器自动执行这个匿名函数,因为这些符号的运算级别都是高的
(function(){... })() 或 (function(){...}()) 也有相同效果

$(function(){ }) 的意义
是 $(document).ready(function(){ }) 的缩写,是 D...

JS函数柯里化

有哪些好处
1. 参数复用
// 正常正则验证字符串 reg.test(txt)

// 函数封装后
function check(reg, txt) {
return reg.test(txt)
}

check(/\d+/g, 'test') //false
check(/[a-z]+/g, 'test') //true

// Currying后
function...

JS 中函数的定义和调用方式

一、函数的定义
1、定义函数(也叫命名函数)
function fn(){};

//ES6 中的新定义,一般也使用这种方式
fn(){};
 
2、函数表达式(匿名函数)
let fun = function(){};
 
3、利用 new Function()('参数1','参数2','函数体'),一般不会用这种方式来定义函数,但应该注意的是:所有的函数都是 Functi...

文章标题:【JavaScript】JS 中实现方法重载
文章链接:https://www.dianjilingqu.com/50951.html
本文章来源于网络,版权归原作者所有,如果本站文章侵犯了您的权益,请联系我们删除,联系邮箱:saisai#email.cn,感谢支持理解。
THE END
< <上一篇
下一篇>>