你所不知道的javascript函数重载

本文内容基本来自于JavaScript Ninja一书(79页),讲道理,我看懂那个方法都费了好大劲,也不知道理解的对不对,有大佬有好的想法可以供我参考参考会不胜感激~

javascript函数重载不同于其他语言的函数重载,它其实没有真正意义上的重载,只是通过传入的参数进行判断来模拟函数重载。

基本上有以下三种方法:

1、通用方法,根据传入参数的类型执行不同的操作。

2、通过某些特定参数是否存在来进行判断。

3、通过传入参数的个数进行判断。

接下来我们来看一下第三种方法

可能你会想到下面这种写法:

var ninja = {
    whatever: function() {
        switch(arguments.length) {
            case 0: 
                /*do something*/
                break;
            case 1:
                /*do something else*/
                break;
            case 2:
                /*do yet something else*/
                break;
        //and so on ...
        }
    }
}

这种方式,通过arguments参数获取实际传入的参数个数进行判断,每一种情况都会执行不同的操作。但是这种判断方式看起来不是那么整洁。

      假设出另外一种方式,如下思路:

var ninja = {};
addMethod(ninja, 'whatever', function() {/*do something*/});
addMethod(ninja, 'whatever', function() {/*do something else*/});
addMethod(ninja, 'whatever', function() {/*do yet something else*/});

 

        先创建一个对象,然后使用同样的名称(whatever)将方法添加到该对象上,只不过每个重载的函数都是单独的。注意每个重载函数的参数个数都不相同。这样看起来整洁多了,接下来创建这个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);
        }
    }
}

        addMethod()的第一次调用将创建一个新匿名函数,传入零个参数进行调用的时候将会调用该fn函数。由于此时ninja是一个新对象,所以这时候不用担心之前创建的方法。

        第二次调用addMethod()的时候,首先将之前的同名函数保存到一个变量old中,然后将新创建的匿名函数作为方法。新方法首先检查传入的参数个数是否为1,如果是,就调用刚才传入的fn函数;如果不是,则重新调用存储在old上的函数,重新调用该函数时,将会再次检查参数个数是否为零,继而调用参数个数为零的fn版本的函数。

        第三次调用addMethod()的时候,传入了一个接收两个参数的fn函数,然后判断逻辑相同:创建一个匿名函数作为方法,判断如果传入参数的个数为2个,则调用2个参数的fn函数,否则递归调用存储在old中的函数(此时old.length==1)。注:这个地方其实一直不太理解,在后面调用的时候是怎么个执行逻辑?

下面是测试代码:

    var ninjas = { //创建一个基础对象,实现加载一些测试数据
        values: ["Dean Edwards", "Sam Stephenson", "Alex Russell"]
    }
    addMethod(ninjas, "find", function () {
        //在基础对象上绑定一个无参数方法
        return this.values;
    })
    addMethod(ninjas, "find", function (name) {
        //在基础对象上绑定一个单参数的方法
        var ret = [];
        for (var i = 0; i < this.values.length; i++) {
            if (this.values[i].indexOf(name) == 0) {
                ret.push(this.values[i])
            }
        }
        return ret;
    })
    addMethod(ninjas, "find", function (first, last) {
        //在基础对象上绑定两个参数的方法
        var ret = [];
        for (var i = 0; i < this.values.length; i++) {
            if (this.values[i] == (first + " " + last)) {
                ret.push(this.values[i]);
            };
        }
        return ret;
    })
    console.log(ninjas.find().length);  //3
    console.log(ninjas.find("Sam").length);     //1
    console.log(ninjas.find("Dean", "Edwards").length);     //1
    console.log(ninjas.find("Aelx", "Russell", "Jr"));      //undefined

 我们声明并绑定的三个版本的find()方法。

1、第一个方法期待没有参数,并返回所有的ninjas;

2、第二个方法期望接收一个参数,并返回所有以传入文本开头的ninjas;

3、第三个方法期望接收两个参数,返回姓氏和名字都匹配所传入字符串参数的ninjas;

这些绑定函数实际上并没有存储于任何典型的数据结构中,而是在闭包里作为块引用进行存储。

需要注意的是:

1、重载只适用于不同数量的参数,但并不区分类型、参数名称或其他东西。这些才是我们经常想做的事情。

2、这样的重载方法会有一些函数调用的开销(递归调用),有高性能要求的时候需要考虑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值