关于Javascript的函数重载问题

在Javascript与Java等语言不同,它自身没有重载的具体方法,但我们可以利用Javascript的特性来完成重载的效果

1.什么是重载

重载,简单说,就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。

2.Javascript如何实现重载

方法一:利用函数的arguments来完成函数的重载

1
2
3
4
5
6
7
8
9
10
11
12
//函数的声明
function overLoading() {
  // 根据arguments.length,对不同的值进行不同的操作
  switch(arguments.length) {
    case 0: console.log('无参');
      break;
    case 1: console.log('一个参数');
      break;
    case 2: console.log('两个参数');
break;
}
}
1
2
3
4
//函数的调用
overLoading(); //结果:无参
overLoading(1); //结果:一个参数
overLoading(1,2); //结果:两个参数

方法二:《Secrets of the JavaScript Ninja》中的方法

重载方法实例:

1
2
3
4
5
6
7
8
9
10
11
12
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函数,简单的理解,就是给某个object,添加一个指定name的函数fn。它利用了闭包,可以通过old变量将先后绑定的函数链接起来。

你可以这样使用addMethod函数,将find函数直接添加到每个对象实例:

1
2
3
4
5
6
7
8
9
10
11
function Users(){
addMethod(this, "find", function(){
// Find All
});
addMethod(this, "find", function(name){
// Find a user by name
});
addMethod(this, "find", function(first, last){
// Find a user by first and last name
});
}

你也可以将find函数添加到对象的prototype,这样所有对象实例将共享find函数:

1
2
3
4
5
6
7
8
9
10
11
function Users(){
addMethod(Users.prototype, "find", function(){
// Find all users...
});
addMethod(Users.prototype, "find", function(name){
// Find a user by name
});
addMethod(Users.prototype, "find", function(first, last){
// Find a user by first and last name
});
}

users对象的find方法成功实现了重载,可以根据不同的输入调用不同的函数:

1
2
3
4
5
var users = new Users();
users.find(); // Finds all
users.find("John"); // Finds users by name
users.find("John", "Resig"); // Finds users by first and last name
users.find("John", "E", "Resig"); // Does nothing

这种方法有一些明显的缺陷:

  • 重载只能处理输入参数个数不同的情况,它不能区分参数的类型、名称等其他要素。(ECMAScript 4计划支持这一特性,称作Multimethods,然而该版本已被放弃)。
  • 重载过的函数将会有一些额外的负载,对于性能要求比较高的应用,使用这个方法要慎重考虑。

addMethod函数的秘诀之一在于fn.length。或许很多人并不清楚,所有函数都有一个length属性,它的值等于定义函数时的参数个数。比如,当你定义的函数只有1个参数时,其length属性为1:

1
(function(foo){}).length == 1

如果你担心只绑定单个函数时的性能问题,你可以使用如下addMethod函数:

1
2
3
4
5
6
7
8
9
10
11
12
function addMethod(object, name, fn){
var old = object[ name ];
if ( old )
object[ name ] = function(){
if ( fn.length == arguments.length )
return fn.apply( this, arguments );
else if ( typeof old == 'function' )
return old.apply( this, arguments );
};
else
object[ name ] = fn;
}

这样绑定第一个函数时,将不会有额外的操作,既简单又快速。当绑定更多函数时,则与原addMethod函数一样,会有额外的性能损失。

这样做还有一个额外的好处:对于那些参数个数不符合要求的函数调用,将统一又第一个绑定的函数处理。这时调用find方法的输出如下:

1
2
3
4
5
var users = new Users();
users.find(); // Finds all
users.find("John"); // Finds users by name
users.find("John", "Resig"); // Finds users by first and last name
users.find("John", "E", "Resig"); // Finds all
× 请我吃糖~
打赏二维码