JS中的函数重载 实参 形参 arguments

本文讨论了JavaScript中不存在函数重载的情况,并解释了原因。通过arguments对象,介绍了函数实参和形参的区别。文章还展示了如何通过特定方式实现类似函数重载的功能,并给出了具体的实现代码和示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Java中,方法可以进行重载

function add(int a,int b){
    //代码块
}
function add(int a,int b,int c){
    //代码块
}

调用的时候,会根据传入参数的不同,自动调用不同的方法。

那么在JS中呢?

如果在js中存在一个方法kid(p1,p2,p3),在别处进行调用的时候,少传了一个参数p3,会是什么结果呢?

function kid(p1,p2,p3){
    console.info(p1);
    console.info(p2);
    console.info(p3);
}


kid("This is the first parameter","This is the second parameter","This is the third parameter");
console.info("==============");
kid("This is the first parameter","This is the second parameter");

结果如下:


This is the first parameter         test.js:4 
This is the second parameter        test.js:5 
This is the third parameter         test.js:6 
==============                      test.js:11 
This is the first parameter         test.js:4 
This is the second parameter        test.js:5 
undefined                           test.js:6 

在最后一个参数处,直接打印除了undefined,并且没有报错。

那么如果出现3个名字一样,参数不一样的方法呢?

function kid(p1,p2,p3){
    console.info("this is parameter[3] method");
    console.info(p1);
    console.info(p2);
    console.info(p3);
}
function kid(p1){
    console.info("this is parameter[1] method");
    console.info(p1);
}
function kid(p1,p2,p3,p4){
    console.info("this is parameter[4] method");
    console.info(p1);
    console.info(p2);
    console.info(p3);
    console.info(p4);	
}

kid("This is the first parameter","This is the second parameter","This is the third parameter");
console.info("==============");
kid("This is the first parameter","This is the second parameter");

 

结果如下:

this is parameter[4] method   test.js:14
This is the first parameter   test.js:15
This is the second parameter  test.js:16
This is the third parameter   test.js:17
undefined                     test.js:18
==============                test.js:21
this is parameter[4] method   test.js:14
This is the first parameter   test.js:15
This is the second parameter  test.js:16
undefined                     test.js:17
undefined                     test.js:18 

最后查询过后,原因是:

在JS中,是不存在函数重载的。它是按照声明的顺序执行的,即如果存在同名函数,执行的是最后一个声明的函数,而前面的函数会被覆盖。 

JS中没有函数重载的原因有:

  • 在JS中,函数默认有一个arguments数组对象的参数,所以实际传入的参数个数并不重要
  • JS中,函数的实质是对象,函数名是指针

而且在JS的函数中,方法不仅有arguments数组对象的参数,还有function自带的构造函数的参数:

function kid(p1,p2,p3){
    console.info("this is parameter[3] method");
    console.info("this is method's function parameter number is " + kid.length);
    console.info("this is method's arguments parameter number is " + arguments.length);
    console.info(p1);
    console.info(p2);
    console.info(p3);
}
console.info("==============");
kid("This is the first parameter","This is the second parameter");

结果是:

this is parameter[3] method                           test.js:27 
this is method's function parameter number is 3       test.js:28 
this is method's arguments parameter number is 2      test.js:29 
This is the first parameter                           test.js:30 
This is the second parameter                          test.js:31 
undefined                                             test.js:32 

很明显,方法的function的长度length不会受参的个数影响而改变(可以理解为形参),而arguments的长度length是随入参的实际个数变化的(可以理解为实参)。

例如,实参变多了:

function kid(p1,p2,p3){
	console.info("this is parameter[3] method");
	console.info("this is method's arguments parameter number is " + arguments.length);
	for(i=0;i<arguments.length;i++){
		console.info(arguments[i])
	}
}
console.info("==============");
kid("This is the first parameter","This is the second parameter","11","22","33","44");

结果如下:

==============
this is parameter[3] method                           test.js:6 
this is method's arguments parameter number is 6      test.js:7 
This is the first parameter                           test.js:9 
This is the second parameter                          test.js:9 
11                                                    test.js:9 
22                                                    test.js:9 
33                                                    test.js:9 
44                                                    test.js:9 

那么如何在JS中实现重载呢,网上有很多答案,最好的就是JQuery之父John Resig的答案:

 

我们现在有这样的一个需求,有一个people对象,里面存着一些人名,如下:

var people = {
  values: ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"]
};


    我们希望people对象拥有一个find方法,当不传任何参数时,就会把people.values里面的所有元素返回来;当传一个参数时,就把first-name跟这个参数匹配的元素返回来;当传两个参数时,则把first-name和last-name都匹配的才返回来。因为find方法是根据参数的个数不同而执行不同的操作的,所以,我们希望有一个addMethod方法,能够如下的为people添加find的重载:

addMethod(people, "find", function() {}); /*不传参*/
addMethod(people, "find", function(a) {}); /*传一个*/
addMethod(people, "find", function(a, b) {}); /*传两个*/


    这时候问题来了,这个全局的addMethod方法该怎么实现呢?John Resig的实现方法如下,代码不长,但是非常的巧妙:

 

function addMethod(object, name, fn) {
  var old = object[name]; //把前一次添加的方法存在一个临时变量old里面
  object[name] = function() { // 重写了object[name]的方法
    // 如果调用object[name]方法时,传入的参数个数跟预期的一致,则直接调用
    if(fn.length === arguments.length) {
      return fn.apply(this, arguments);
    // 否则,判断old是否是函数,如果是,就调用old
    } else if(typeof old === "function") {
      return old.apply(this, arguments);
    }
  }
}


    现在,我们一起来分析一个这个addMethod函数,它接收3个参数,第一个为要绑定方法的对象,第二个为绑定的方法名称,第三个为需要绑定的方法(一个匿名函数)。函数体的的分析已经在注释里面了。 

    OK,现在这个addMethod方法已经实现了,我们接下来就实现people.find的重载啦!全部代码如下:

//addMethod
function addMethod(object, name, fn) {
  var old = object[name];
  object[name] = function() {
    if(fn.length === arguments.length) {
      return fn.apply(this, arguments);
    } else if(typeof old === "function") {
      return old.apply(this, arguments);
    }
  }
}
 
 
var people = {
  values: ["Dean Edwards", "Alex Russell", "Dean Tom"]
};
 
/* 下面开始通过addMethod来实现对people.find方法的重载 */
 
// 不传参数时,返回peopld.values里面的所有元素
addMethod(people, "find", function() {
  return this.values;
});
 
// 传一个参数时,按first-name的匹配进行返回
addMethod(people, "find", function(firstName) {
  var ret = [];
  for(var i = 0; i < this.values.length; i++) {
    if(this.values[i].indexOf(firstName) === 0) {
      ret.push(this.values[i]);
    }
  }
  return ret;
});
 
// 传两个参数时,返回first-name和last-name都匹配的元素
addMethod(people, "find", function(firstName, lastName) {
  var ret = [];
  for(var i = 0; i < this.values.length; i++) {
    if(this.values[i] === (firstName + " " + lastName)) {
      ret.push(this.values[i]);
    }
  }
  return ret;
});
 
// 测试:
console.log(people.find()); //["Dean Edwards", "Alex Russell", "Dean Tom"]
console.log(people.find("Dean")); //["Dean Edwards", "Dean Tom"]
console.log(people.find("Dean Edwards")); //["Dean Edwards"]

 

更为简单点的理解就是:

你想给一个 Person 对象实现这么一个方法,名字叫calculate: 
* 当传入一个参数,返回该参数 
* 当传入两个参数,返回参数的积 
* 当传入三个参数,返回参数的和

这三个函数分别写出来应该是这样:

calculate1 (a) {return a;}

calculate2 (a, b) {return a*b;}

calculate3 (a, b, c) {return a+b+c;}

用 John Resig 给我们提供的 addMethod 方法我们只需要这样写,这样重载就完成了。

addMethod(Person.prototype, calculate, calculate1);
addMethod(Person.prototype, calculate, calculate2);
addMethod(Person.prototype, calculate, calculate3);

重载的实现方法还是一如既往:利用 old 变量,将绑定前后的函数连接起来。

function addMethod(object, name, fn){
    var old = object[ name ];
    object[ name ] = function(){
        if ( fn.length == arguments.length )
            return fn.apply( this, arguments );
        else if ( typeof old == 'function' )
            return old.apply( this, arguments );
    };
}

 

使用的JS和html如下
test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="test.js"></script>
</head>
<body>

</body>
</html>

test.js  可以根据不同测试用例注释掉不需要的代码



function kid(p1,p2,p3){
	console.info("this is parameter[3] method");
    console.info(p1);
    console.info(p2);
    console.info(p3);
}
function kid(p1){
	console.info("this is parameter[1] method");
    console.info(p1);
}
function kid(p1,p2,p3,p4){
	console.info("this is parameter[4] method");
    console.info(p1);
    console.info(p2);
    console.info(p3);
    console.info(p4);	
}
kid("This is the first parameter","This is the second parameter","This is the third parameter");
console.info("==============");
kid("This is the first parameter","This is the second parameter");



function kid(p1,p2,p3){
	console.info("this is parameter[3] method");
	console.info("this is method's function parameter number is " + kid.length);
	console.info("this is method's arguments parameter number is " + arguments.length);
    console.info(p1);
    console.info(p2);
    console.info(p3);
	for(i=0;i<arguments,length;i++){
		console.info(arguments[i])
	}
}
console.info("==============");
kid("This is the first parameter","This is the second parameter","11","22","33","44");

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值