提供javascript配置接口

2013/02/14 00:29
阅读数 228
    我一直认为正确的并且坚持的事情是当写代码的时候应该把代码中所有可以定制的部分分离出来形成一个配置对象。
    下面是我这些天写的一个简单js:
var module = function() {
    // configuration, change things here
    var config = {
        CSS: {
            classes: {
                hover: 'hover',
                active: 'current',
                jsEnabled: 'js'
            },
            ids: {
                container: 'maincontainer'
            }
        },
        timeout: 2000,
        userID: 'chrisheilman'
    };
    
    // start of main code
    function init() {
        
    };
    
    // more method and other code ...
    
    return {
        init: init
    };
}();
module.init();
    这样做的优点显而易见:
  • 使用者无需查看整个代码从而判断哪些内容需要修改
  • 清晰的分离,达到“在一处修改你想要设置的东西”和“只接触你正在做的内容而不影响其他”的目的,从而能使更多的开发者重用你的代码
  • 使代码与其他开发层只有一个唯一的交集,例如设置你要使用的HTML元素ID和用于生成元素的CSS的classname
  • 在一个地方写配置信息使本地化更容易,并且提高脚本执行速度

    我觉得这种写法已经满足需要,直到一天,Ara Pehlivanian 要求程序在执行时能够重写配置文件信息,就像YUI里YAHOO.util.Config能实现的功能一样。他的要求当然是正确的,有时你想改变配置并且重新启动脚本(另外一种办法是写一个模块)。
    最简单的方法,就是将配置对象公开:

var module = function() {
    // configuration, change things here
    var config = {
        CSS: {
            classes: {
                hover: 'hover',
                active: 'current',
                jsEnabled: 'js'
            },
            ids: {
                container: 'maincontainer'
            }
        },
        timeout: 2000,
        userID: 'chrisheilman'
    };
    
    // start of main code
    function init() {
        
    };
    
    // more method and other code ...
    
    return {
        init: init,
        config: config
    };
}();
     重写配置的语句要放在调用init()方法前面:
module.config.CSS.ids.container = 'header';
module.config.userID = 'alanwhite';
module.init();
    然而,Ara认为提供一个对象作为参数传递给init()方法来覆盖一些属性要更方便。你可以通过检查这个对象,遍历它的属性,递归地试图找到和匹配到配置里的一个属性:
var module = function() {
    // configuration, change things here
    var config = {
        CSS: {
            classes: {
                hover: 'hover',
                active: 'current',
                jsEnabled: 'js'
            },
            ids: {
                container: 'maincontainer'
            }
        },
        timeout: 2000,
        userID: 'chrisheilman'
    };
    
    // start of main code
    function init() {
        // check if the first argument is an object
        var a = arguments;
        if(isObj(a[0])) {
            var cfg = a[0];
            // loop through arguments and alter the configuration
            for (var i in cfg) {
                setConfig(config, i, cfg[i]);
            }
        }
    };
    
    function setConfig(o, p, v) {
        // loop through all the properties of he object
        for (var i in o) {
            // when the value is an object call this function recursively
            if(isObj(o[i])) {
                setConfig(o[i], p, v);
            }else {
                if(i === p) {
                    o[p] = v;
                }
            }
        }
    }
    
    // tests if a parameter is an object(and not an array)
    function isObj(o) {
        return (typeof o === 'object' && typeof o.splice !== 'function');
    }
    
    // more method and other code ...
    
    // make init a pubic method
    return {
        init: init
    };
}();
module.init({
    container: 'header',
    'timeout': 1000
});

    当所有配置属性是唯一的时候,它会顺利执行。但是当一个嵌套对象内的属性名在另外的更高一级的嵌套对象内已有同名属性时,则会重写属性失败。为了应对这样的情况,我们可以传递一个带有路径的字符串作为属性名。然后根据'.'对字符串进行分割,使用eval()方法来确保以正确的数据格式返回值。像下面这样:

var module = function() {
    // configuration, change things here
    var config = {
        CSS : {
            classes : {
                hover : 'hover',
                active : 'current',
                jsEnabled : 'js'
            },
            ids : {
                container : 'maincontainer'
            }
        },
        timeout : 2000,
        userID : 'chrisheilman'
    };

    // start of main code
    function init() {
        if (isObj(arguments[0])) {
            var cfg = arguments[0];
            for (var i in cfg) {
                if (i.indexOf('.') !== -1) {
                    var str = '["' + i.replace(/\./g, '"]["') + '"]';
                    var val = getValue(cfg[i]);
                    eval('config' + str + '=' + val);
                } else {
                    setConfig(config, i, cfg[i]);
                }
            }
        }
    };

    function setConfig(o, p, v) {
        // loop through all the properties of he object
        for (var i in o) {
            // when the value is an object call this function recursively
            if (isObj(o[i])) {
                setConfig(o[i], p, v);
            } else {
                if (i === p) {
                    o[p] = v;
                }
            }
        }
    }

    // tests if a parameter is an object(and not an array)
    function isObj(o) {
        return ( typeof o === 'object' && typeof o.splice !== 'function');
    }

    function getValue(v) {
        switch(typeof v) {
            case 'string':
                return "'" + v + "'";
                break;
            case 'number':
                return v;
                break;
            case 'object':
                if ( typeof v.splice === 'function') {
                    return '[' + v + ']';
                } else {
                    return '{' + v + '}';
                }
            case NaN:
                break;
        }
    }

    // more method and other code ...
    function getConfig() {
        return config;
    }

    // make init a pubic method
    return {
        init : init,
        getConfig : getConfig
    };
}();
module.init({
    'container' : 'header',
    'CSS.classes.active' : 'now',
    'timeout' : 1000
});
console.log(module.getConfig());
     为了可读性和可维护性,我把关于修改配置的代码写在一个单独的模块里:
var module = function() {
    // configuration, change things here
    var config = {
        CSS : {
            classes : {
                hover : 'hover',
                active : 'current',
                jsEnabled : 'js'
            },
            ids : {
                container : 'maincontainer'
            }
        },
        timeout : 2000,
        userID : 'chrisheilman'
    };

    // start of main code
    function init() {
        changeConfig.set(arguments[0]);
        console.log(config);
    };
    
    var changeConfig = function() {
        function set(o) {
            var reg = /\./g;
            if(isObj(o)) {
                for (var i in o) {
                    if(i.indexOf('.') !== -1){
                        var str = '["' + i.replace(reg, '"]["') + '"]';
                        var val = getValue(o[i]);
                        eval('config' + str + '=' + val);
                    }else {
                        findProperty(config,i,o[i]);
                    }
                }
            }
        }
        
        function findProperty(o, p, v) {
            for (var i in o) {
                if(isObj(o[i])) {
                    findProperty(o[i], p, v);
                }else {
                    if(i === p) {
                        o[p] = v;
                    }
                }
            }
        }
        
        function isObj(o) {
            return ( typeof o === 'object' && typeof o.splice !== 'function');
        }
        
        function getValue(v) {
            switch(typeof v) {
                case 'string':
                    return "'" + v + "'";
                    break;
                case 'number':
                    return v;
                    break;
                case 'object':
                    if ( typeof v.splice === 'function') {
                        return '[' + v + ']';
                    } else {
                        return '{' + v + '}';
                    }
                case NaN:
                    break;
            }
        }
        
        return {set: set};
    }();

    // more method and other code ...

    // make init a pubic method
    return {
        init: init
    };
}();
module.init({
    'container': 'header',
    'CSS.classes.active': 'now',
    'timeout': 1000
});
    这就是提供js配置对象并且能在init()方法运行时动态修改配置的一种方法,你能想到更好的方法吗?

展开阅读全文
打赏
0
6 收藏
分享
加载中
BlinkCG博主

引用来自“车开源”的评论

引用来自“web天空”的评论

引用来自“车开源”的评论

用OSC安卓客户端看文章最头疼就是:文章里有代码,乱成一堆。@红薯 这个问题要重视呢。

你屏幕多大呢?我小米看不会

我也用小米,代码块全部没换行,看得辛苦。

我自己的LG上显示也是乱的。确实很纠结
2013/02/16 12:38
回复
举报

引用来自“web天空”的评论

引用来自“车开源”的评论

用OSC安卓客户端看文章最头疼就是:文章里有代码,乱成一堆。@红薯 这个问题要重视呢。

你屏幕多大呢?我小米看不会

我也用小米,代码块全部没换行,看得辛苦。
2013/02/15 18:47
回复
举报

引用来自“车开源”的评论

用OSC安卓客户端看文章最头疼就是:文章里有代码,乱成一堆。@红薯 这个问题要重视呢。

你屏幕多大呢?我小米看不会
2013/02/15 09:19
回复
举报
用OSC安卓客户端看文章最头疼就是:文章里有代码,乱成一堆。@红薯 这个问题要重视呢。
2013/02/15 08:35
回复
举报
更多评论
打赏
4 评论
6 收藏
0
分享
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部