您的位置:首页 > Web前端 > JavaScript

关于理解重载的深入学习

2016-06-26 23:55 393 查看
在看到《JavaScript高级程序设计》 没有重载 这部分时,想更加深入了解下重载,于是在网上搜集了一些信息,以下是这部分的总结整理:

没有重载:JavaScript函数不能像传统意义上那样实现重载。而在其他语言中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。JavaScript函数没有签名,因为其参数是由包含零或多个值得数组来表示的。而没有函数签名真正的重载是不可能做到的。

虽然没有重载,但我们通常可以这样来实现模拟重载:

1判断传入参数的个数

Javascript的每个函数都带有一个仅在这个函数范围内作用的变量——arguments,它是一个包含所有传给函数的参数的伪数组。为什么是伪数组?——你不能修改它,也不能用push来添加新元素等。但是你可以访问其中的元素,并且同时具有.length属性。有了length属性,我们就可以很方便的知道函数传入了几个参数。

function send( message, who ) {

if( arguments.length >= 2 ) {

console.log("你对" + who + "说:" + message);

}

else {

console.log("你对大家说:" + message);

}

}

2判断传入参数的类型

如果我们在函数中并没有提供参数,那么message和who的值一定为'undefined'。我们可以使用typeof
message = 'undefined'来判断是否传入了参数。

function send( message ) {

if( typeof message === 'undefined' ) {

console.log("ERROR:错误的信息内容");

}

else {

console.log("你说:" + message);

}

}

下面是我看到的一种更好的方法,目前还不太能完全理解:

JQuery之父John Resig写的《secrets of the JavaScript ninja》里的一个绝佳巧妙的方法!那种方法充分的利用了闭包的特性!

在介绍这个方法之前,我们先来看看外国人名字组成哈,比如,John Resig,John是first-name,Resig是last-name,就相当于我们的姓名由姓和名组成一样。我们现在有这样的一个需求,有一个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"]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript