JS中实现重载

javascript不能支持函数的重载,如下:

代码如下:

<script language="JavaScript"> 
function f(length) 
{ 
    alert("高为:"+length); 
} 

function f(length,width) 
{ 
    alert("高为:"+length+",宽为:"+width); 
} 
</srcipt>

上面那段代码其实是行不通的,因为函数定义时的参数个数和函数调用时的参数个数没有任何关系。 在函数中可以用f.arguments[0]和f.arguments[1]得到调用时传入的第一和第二个参数,所以定义function(length),后面用f(10,10)调用是没有问题的。所以在上面这段代码中,第二个函数是永远不可能被调用到的,那么,要怎样才能实现像函数重载那样的功能呢?
那就是在函数定义中用f.arguments.length判断一下调用时传入的参数个数。然后对不同的情况采用不同的处理方式。
如下:

代码如下:

<script language="JavaScript"> 
function f() 
{ 
    var len= arguments.length; 
    if(2 == len) 
    { 
        var length = arguments[0]; 
        var width = arguments[1]; 
        f2(length,width); 
    } 
    else 
    { 
        var length = arguments[0]; 
        f1(length); 
    } 
} 
 function f1(length) 
  { 
     alert("高为:"+length); 
  } 

  function f2(length,width) 
  { 
     alert("高为:"+length+",宽为:"+width); 
 } 
  </srcipt>

这样,你就可以给函数f()传入一个参数也可以传入两个参数了,比如f(10)和f(10,10);
个人觉得,这样虽然可以实现重载,但也不是很好用,我们可以根据具体情况在一个函数中实现重载,如果要重载的两个函数相差较大,那就保留两个函数,而如果两个函数的实现基本差不多,那么可以在一个函数中进行判断,处理不同的部分,而不需要像上面那样写成三个函数,如下:

代码如下:

<script language="JavaScript"> 
function f(length) 
{ 
    var len= arguments.length; 
    if(2== len) 
    { 
        var width = arguments[1]; 
        alert("高为:"+length+",宽为:"+width); 
    } 
    else 
    { 
        alert("高为:"+length); 
    } 
} 
</srcipt>

我们现在有这样的一个需求,有一个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"]