首页 > 代码库 > 利用递归统一化函数参数的不固定数据类型

利用递归统一化函数参数的不固定数据类型

为了用户调用函数时更方便和灵活,所以我们定义的参数需要不固定数据类型,比如像这样:

mylibs.on(‘event‘,fn);

mylibs.on({
    ‘event1‘:fn1,
    ‘event2‘:fn2,
    ‘event3‘:fn3
});

mylibs.on(‘event1 event2 event3‘,fn);

这是一个自定义事件的例子,有三种传参的方式:1、事件名+回调   2、传递一个对象包含事件名和回调    3、多个事件名+一个回调

你觉得这个函数怎么写才好呢,也许大多数人首先想到的是统一数据类型再处理具体的逻辑,就像下面这样:

//匹配任何空白符,包括\n,\r,\f,\t,\v等(换行、回车、空格、tab等)var eventSplitter = /\s+/;var mylibs = {    on:function(name, callback, context){        if(typeof name === ‘string‘){            name = {name:callback};        }                    if (eventSplitter.test(name)) {            var names = name.split(eventSplitter),                name = {};            for (var i = 0, length = names.length; i < length; i++) {                name[names[i]] = callback;            }        }                    //统一好了数据类型则执行循环(默认数据类型是对象,所以在上面不做判断)        for(var key in name){            //具体逻辑......        }        return this;    }};

 

这种写法看似不错,先统一处理数据类型,解决了参数不同的问题。不过函数看上去稍显臃肿,如果参数再增加几种类型,那么相应的也会在函数体内增加判断语句,并且把具体的逻辑代码放在for循环内也不是一种优雅的做法。

我们可以尝试一下把判断语句提炼出来,写在一个单独的函数里。

var mylibs = {    on:function(name, callback, context){        name = this.eventsApi(name,callback);        for(var key in name){            //具体逻辑......        }        return this;    },    eventsApi:function(name,callback){        if(typeof name === ‘string‘){            return {name:callback};        }            if (eventSplitter.test(name)) {            var names = name.split(eventSplitter),                name = {};            for (var i = 0, length = names.length; i < length; i++) {                name[names[i]] = callback;            }            return name;        }        return name;    }};

创建了eventsApi函数来对数据类型做统一处理,很明显on函数已经不臃肿了,2个函数各司其职。但是on函数的具体逻辑代码仍然在for循环内,我们得想办法把它抽离出来。

解决的办法可以利用递归,我们先处理一下eventsApi函数。

eventsApi:function(obj,action,name,rest){    if (!name) return true;    if(typeof name === ‘object‘){        for(var key in name){            obj[action].apply(obj,[key,name[key]].concat(rest));        }        return false;    }    if (eventSplitter.test(name)) {        var names = name.split(eventSplitter);        for (var i = 0, length = names.length; i < length; i++) {            obj[action].apply(obj, [names[i]].concat(rest));        }        return false;    }    return true;}

是不是眼前一亮,eventsApi函数并没有统一处理数据类型,而是直接调用on函数,此时on函数变成了一个固定数据类型的函数了,其实就是上面第一种传参的形式:一个事件名+回调。

我们看一下完整的代码加深理解吧。

//匹配任何空白符,包括\n,\r,\f,\t,\v等(换行、回车、空格、tab等)var eventSplitter = /\s+/;var mylibs = {    on:function(name, callback, context){        if (!this.eventsApi(this, ‘on‘, name, [callback, context]) || !callback) return this;        //具体逻辑......        return this;    },    eventsApi:function(obj,action,name,rest){        if (!name) return true;        if(typeof name === ‘object‘){            for(var key in name){                obj[action].apply(obj,[key,name[key]].concat(rest));            }            return false;        }        if (eventSplitter.test(name)) {            var names = name.split(eventSplitter);            for (var i = 0, length = names.length; i < length; i++) {                obj[action].apply(obj, [names[i]].concat(rest));            }            return false;        }        return true;    }};//调用:mylibs.on(‘event‘,fn);mylibs.on({    ‘event1‘:fn1,    ‘event2‘:fn2,    ‘event3‘:fn3});mylibs.on(‘event1 event2 event3‘,fn);

 

利用递归统一化函数参数的不固定数据类型