codeing or artist ?
记得大学第一节编程课,教授说,"如果一件事儿有对错,那么是科学。如果有美丑好坏,那么是艺术。" 一个能顺利运行还能让人阅读时体验思维美妙的代码,就是艺术和科学的结合。能运行的程序并不是好程序,能当作文章来读的才是。在我看来代码是一种特殊的文体,程序猿其实会写诗。

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

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);

 

posted on 2016-09-16 16:50  codeing-or-artist-??  阅读(429)  评论(0编辑  收藏  举报