js实现重载(参数类型和参数数量以及参数顺序)

js实现重载

  • 使用javascript(es6)来模拟重载(其实也没用多少es6,就是一个let)
  • 这个实现较之一般实现来说,模拟的更像重载,可以根据参数类型和个数来选择相应的函数
  • 核心是eval以及一个对象数组
  • 转载请申明出处

首先的首先

先看看一般重载函数怎么实现的吧,网上一大堆,自己某度就能了解了

首先先上代码(不想看我的思路的人直接拿走用吧)

function reloadGenerator(){
            this.actFns=[];
            let that = this;
            let actObj = function(){
                let inArgs=arguments;
                let typeForFn =that.actFns;
                let l = inArgs.length-1;
                let strArg = "";
                let fn = typeForFn[l];
                for(let i = 0; i<inArgs.length;i++){
                    strArg +=",inArgs["+i+"]";
                    if(fn[queryType(inArgs[i])]){
                        fn = fn[queryType(inArgs[i])]
                    }else{
                        console.log('函数不存在: 要调用的函数不存在');
                    }
                }
                strArg = strArg.substr(1);//获取参数字符串
                let invoca = "fn("+strArg+")";
                eval(invoca);
                //-------***********
                function queryType(arg){
                    if(arg.constructor == String ){
                        return "string";
                    }
                    if(arg.constructor == Number){
                        return "number";
                    }
                    if(arg.constructor == Boolean){
                        return "boolean";
                    }
                    if(arg.constructor == Array){
                        return "array";
                    }
                    if(arg.constructor == Object){
                        return "object";
                    }
                    if(arg.constructor == Function){
                        return "function";
                    }
                    return "undefined";
                }
            }

            this.addReload=function(arg,fn){
                let l = fn.length-1;
                if(!this.actFns[l]){
                    this.actFns[l]={}
                }
                let addObj = this.actFns[l];
                for(let i = 0; i<arg.length; i++){
                    if(i == arg.length-1){
                    //by wyx0k 手动水印haha
                        addObj[arg[i]]=fn;
                    }else{
                        if(!addObj[arg[i]]){
                            addObj[arg[i]]={};
                        }
                    }
                    addObj=addObj[arg[i]];
                }
            }
            this.init = function(){
                return actObj;
            }
            this.remove = function(arr){
                let l = arr.length-1;
                let removeObj = this.actFns[l]
                for(let i = 0; i<arr.length; i++){
                    if(removeObj[arr[i]]){
                        if(i == l){
                            removeObj[arr[i]] = null;
                        }
                        removeObj = removeObj[arr[i]]
                    }else{
                        console.log("函数不存在:无法删除不存在的重载函数");
                        return;
                    }
                }
            }
            if(arguments.length==0){
                return this;
            }
            let args = [];
            let fns = [];
            for (var i = 0; i < arguments.length; i++) {
                args.push(arguments[i][0]);
                fns.push(arguments[i][1]);
            }
            for (let i = 0; i < fns.length; i++) {
                let l = fns[i].length-1;
                if(!this.actFns[l]){
                    this.actFns[l]={}
                }
                let genObj = this.actFns[l];
                for (let k = 0; k < args[i].length; k++) {
                    if(k==args[i].length-1){
                    //by wyx0k 手动水印haha
                        genObj[args[i][k]]=fns[i];
                    }else{
                        if(!genObj[args[i][k]]){
                            genObj[args[i][k]]={};
                        }
                    }
                    genObj = genObj[args[i][k]];
                }
            }
            return actObj;
        }

调用方式

调用可以使用两种方式,一次生成调用(不知道算不算静态调用)和动态调用

一次生成

这种调用的方式,一旦生成了重载函数,就无法改变了.但是一般也就这么用,没事的.
对方不和你说话并向你抛了一段代码

//创建
let test = new reloadGenerator(
                [
                    ['boolean','function'],
                    function(tr,fn){
                        fn(tr)
                    }
                ],
                [
                    ['boolean','number'],
                    function(tr,num){
                        console.log(num+"----------"+tr)
                    }
                ],
                [
                    ['array','object'],
                    function(arr,obj){
                        console.log(obj);
                        console.log(arr.join());
                    }
                ]
            );
        //使用
        test(true,function(t){
            alert(!t);
        });
        test(true,666);
        test([1,2,3],{ok:true,num:123,arr:[{as:123456879}]});

主要呢,就是传一个n个数组进去,一个数组代表定义了一个重载函数,然后呢,每个数组里第一个是重载函数的参数类型(注意这个就相当于定义了参数的顺序\个数\类型),第二个是重载函数的函数体,第二个重载函数的形参要不要写?当然要写了,方便记忆,以及函数里面调用啊.
然后用一个变量接收,这个变量就是生成好了的重载函数了~

动态调用

**如果我的重载函数是不固定的,我一会想多加一个重载函数一会又不想要了(别问我为什么这么不专一),那我咋办?
不要慌,看代码

        let test2 = new reloadGenerator();//如果想要动态的使用,那么就不要在这传参
        test2.addReload(['string','number'],function(name,score){
            alert(name+"----------"+score);
        });
        test2.addReload(['string','number','boolean'],function(name,score,sex){
            alert(name+"----------"+score+"----------"+sex);
        });
        let fn = test2.init();//每次新增了重载函数都要记得init一下哟
        fn('okman',12,true);
        fn('haska',16);
        test2.remove(['string','number','boolean1']);
        fn('okman',12,true);
        test2.remove(['string','number','boolean']);
        // fn('okman',12,true); 没有这个函数了这时会报错

这种方法能够随时新增或者删除重载函数,虽然我感觉这个功能好像作用不是太大,但我还是写了.
0. 注意:不要在实例化的时候传参
1. 每次新增了函数是要进行init的
2. 如果要删除的函数是不存在的不会显式的报错,只会低调的在控制台露一面

思路(以下为思路,懂得人和不想了解的人可以走了)

总体来说呢,非常的简单,我是搜了一下网上的重载实现方法都是千篇一律的那种,而且每次写都要手写条件判断多麻烦呀,我就来写个不一样的吧.
言归正传:思路就是建立一个对象数组,这个对象数组呢,结构是这样的:
1.
先按参数的数量大致的分一下类
[参数数量为1的,
参数数量为2的,
参数数量为3的,
参数数量为4的,
]
2.
然后数组的每个位置上是一个对象,这个对象呢就用咱们实际的 需要的 重载的 函数的 参数来当对象名.
说着可能麻烦,我将用一个例子来说明上面的两点.
假如我们需要三个重载函数分别是fn(name,score)和fn(name,sex)和fn(name,score,sex)
那么他们的结构就是

[   ,
    name:{
        score:{fn},
        sex:{fn}
    },
    name:{
        score:{
            sex:{fn}
        }
    }
]

这就是大体的思路了,在这个这个数组中,我们使用参数来导航找到对应的方法这样就能确定参数的类型\个数\以及顺序了.
3.
然后另一个使之成为现实的核心方法是eval,不知道它是啥就某度吧,看w3c文档就行,说的非常明了.

实现

注意:下文使用的方法地图不是特有名词,是我为了方便解释而进行的比喻
然后我们来大概走一下流程,细枝末节就不说了:
1.大概流程就是generator函数(下文就叫生成器了)可以返回一个方法(默认返回生成的方法),判断没有参数传进来就返回自身对象
2.关于生成的方法,会保存一份生成器里面的对象数组我就叫她方法地图了,这个调用重载的过程很象一个在地图上查找路径的过程,我们真正使用的是这个生成的方法

let actObj = function(){
                let inArgs=arguments;
                let typeForFn =that.actFns;
                let l = inArgs.length-1;
                let strArg = "";
                let fn = typeForFn[l];
                for(let i = 0; i<inArgs.length;i++){
                    strArg +=",inArgs["+i+"]";
                    if(fn[queryType(inArgs[i])]){
                        fn = fn[queryType(inArgs[i])]
                    }else{
                        console.log('函数不存在: 要调用的函数不存在');
                    }
                }
                strArg = strArg.substr(1);//获取参数字符串
                let invoca = "fn("+strArg+")";
                eval(invoca);
                //-------***********
                function queryType(arg){
                    if(arg.constructor == String ){
                        return "string";
                    }
                    if(arg.constructor == Number){
                        return "number";
                    }
                    if(arg.constructor == Boolean){
                        return "boolean";
                    }
                    if(arg.constructor == Array){
                        return "array";
                    }
                    if(arg.constructor == Object){
                        return "object";
                    }
                    if(arg.constructor == Function){
                        return "function";
                    }
                    return "undefined";
                }
            }

它里面有个根据参数找到的类型的函数,这个也是比较重要的一点,用来生成在方法地图中查找的路径.
这个方法整个是个什么意思呢?其实就是先根据参数的个数来确定查找的起点(也就是数组的第几个位置),然后用一个对象保存这个起点,遍历参数,根据每个参数生成对应的类型,然后看看能否根据生成的这个类型在方法地图中找到,找到就遍历下一个参数直到找到函数为止,没找到就报错.
看吧是不是很简单,整个生成器还有个比较重要的地方就是生成方法地图,是根据传进来的参数,先根据函数的形参个数来生成方法地图的起点,然后在跟据传进的参数类型数组进行遍历并生成方法地图然后将函数放入地图的每条路径的终点.
最核心的已经讲完了~
剩下的细枝末节就自己看看吧.第一次写博客有点小兴奋,(~ ̄▽ ̄)~ ,不足之处请指正.
By wyx0k |2018.8.27
转载请注明出处

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值