如果想要所有的地方都能访问到同一个变量。我们应该怎么办?在实践中这种场景很多,比如全局的状态管理。

但之前我们也说过,在实际开发中,全局变量是一定不能轻易使用的。那应该怎么办?模块化的思维能帮助我们解决这个问题。

模块化开发是目前最流行,也是必须要掌握的一种开发思路。

而模块化其实是建立在单例模式的基础之上,因此模块化开发其实和闭包息息相关。

而目前流行的模块化开发思路,无论是require,还是ES6的modules,虽然实现的方式不一样,但是核心的思路都是一样的。因此为了方便大家理解模块化的思维,我们这里就以建立在函数自执行基础之上的单例模式为例,与大家一起来感受一下模块化开发的魅力。

首先请记住:每一个单例就是一个模块。

在未来,你可能会被告知,每一个文件,就是一个模块。这里的道理是一模一样的。我们这里把每一个单例模式假象成为一个单独的文件即可。

因此我们这里,通过如下的方式定义一个模块。而变量名就是模块名。

var module_test = (function() {

})();

第二,每一个模块想要与其他模块交互,那么就必须有获取其他模块的能力,例如requirejs中的require与ES6 modules中的import

// require
var $ = require('jquery');

// es6 modules
import $ from 'jquery';

当然,我们这里在定义时模块名就已经是全局变量,所以就省略了这一步。

第三,每一个模块都应该有对外的接口,以保证与其他模块交互的能力。我们这里直接使用return 返回一个字面量对象的方式来对外提供接口即可。

var module_test = (function() {
    ...

    return {
        testfn1: function() {},
        testfn2: function() {}
    }
})();

那么现在我们结合一个简单的案例来走一遍模块化开发的过程。我们这个案例想要实现的功能是每隔一秒,body的背景色就随着一个数字的递增而在固定的三种颜色之间切换。

我们首先创建一个专门用来管理全局状态的模块。这个模块中有一个私有变量保存了所有的状态值,并对位提供了访问与设置这个私有变量的方法。代码如下。

var module_status = (function() {
    var status = {
        number: 0,
        color: null
    }

    var get = function(prop) {
        return status[prop];
    }

    var set = function(prop, value) {
        status[prop] = value;
    }

    return {
        get: get,
        set: set
    }
})();

然后我们再来创建一个模块,这个模块专门负责body背景颜色的改变。

var module_color = (function() {

    // 假装用这种方式执行第二步引入模块 类似于 import state from 'module_status';
    var state = module_status;
    var colors = ['orange', '#ccc', 'pink'];

    function render() {
        var color = colors[state.get('number') % 3];
        document.body.style.backgroundColor = color;
    }

    return {
        render: render
    }

})();

在这个模块中,我们引入了管理状态的模块,并且将颜色的管理与改变方式都定义在该模块中,那么再使用时我们只需要调用render方法就可以了。

接下来我们还要创建另外一个模块来负责显示当前的number值,用于参考与对比。

var module_context = (function() {
    var state = module_status;

    function render() {
        document.body.innerHTML = 'this Number is ' + state.get('number');
    }

    return {
        render: render
    }
})();

OK,这些功能模块都创建完毕之后,最后我们只需要创建一个主模块即可,这个主模块的目的就是借助功能模块,来实现我们想要的效果。

var module_main = (function() {
    var state = module_status;
    var color = module_color;
    var context = module_context;

    setInterval(function() {
        var newNumber = state.get('number') + 1;
        state.set('number', newNumber);

        color.render();
        context.render();
    }, 1000);
})();

如果你有过模块化开发的经验,那么结合前面对于闭包的理解,这段代码就再简单不过了,而如果你是初次正式学习模块化的概念,那么这个例子也是非得值得细细品味的。具体的展示效果,大家把这段代码摘抄到一个html文件的script标签中即可。完整代码如下。


<script>
var module_status = (function() {
    var status = {
        number: 0,
        color: null
    }

    var get = function(prop) {
        return status[prop];
    }

    var set = function(prop, value) {
        status[prop] = value;
    }

    return {
        get: get,
        set: set
    }
})();

var module_color = (function() {

    // 假装用这种方式执行第二步引入模块 类似于 import state from 'module_status';
    var state = module_status;
    var colors = ['orange', '#ccc', 'pink'];

    function render() {
        var color = colors[state.get('number') % 3];
        document.body.style.backgroundColor = color;
    }

    return {
        render: render
    }

})();

var module_context = (function() {
    var state = module_status;

    function render() {
        document.body.innerHTML = 'this Number is ' + state.get('number');
    }

    return {
        render: render
    }
})();

var module_main = (function() {
    var state = module_status;
    var color = module_color;
    var context = module_context;

    setInterval(function() {
        var newNumber = state.get('number') + 1;
        state.set('number', newNumber);

        color.render();
        context.render();
    }, 1000);
})();

</script>

这里就先以这个简单的例子让大家初步感受一下模块化的开发思维,等后续的章节学习了更加规范的模块化语法之后,我们再结合涉及面更广的实际案例来学习。当然,这里介绍的模块化思维与开发方式大家仍然可以用在稍微简单一点的页面中运用(或者你的项目还没用到构建工具),相信这样的思路来开发代码,肯定要比把代码从头码到尾更加的合理。

results matching ""

    No results matching ""