首页 > 代码库 > 模块化JavaScript设计模式(一)

模块化JavaScript设计模式(一)

在可扩展JavaScript的世界里,如果我们说一个应用程序是模块化(modular)的,那么通常意味着它是由一系列存储于模块中的高度解耦,不同的功能片段组成。在可能的情况下,通过一处依赖性,松耦合可以使应用程序的可维护性更加简单。 如果有效地实现了这点,就很容易地了解一部分如何影响另一个部分。


异步模块定义(AMD)的整体目标是提供模块化的JavaScript解决方案,以便开发者使用。诞生于使用XHR+eval的Dojo开发经验,这种格式的支持者希望能够避免未来的任何解决方案受到过去解决方案缺点的影响。 AMD模块格式本身就是对定义模块的建议,其模块和依赖都将可以进行异步加载。

AMD最开始是CommonJS重模块格式的草案规范,但由于没有达到广泛的一致,这种格式的进一步发展就转移到了amdjs社区(https://github.com/amdjs)。


一、模块入门

关于AMD有两个关键概念是值得我们注意的,他们是用于模块定义的define方法和用于处理依赖加载的require方法。试用一下方法,define用于定义已命名或未命名模块:

define(
    module_id /*可选*/,
    [dependencies] /*可选*/,
    definition function /*function for instantiating the module or object实例化模块或对象的函数*/
)


module_id是一个可选参数,它通常只在非AMD 连接工具被使用时才需要。当遗漏这个参数时,我们称这个模块未匿名的(anonymous)。

当使用这个匿名模块时,模块身份的概念是DRY,以便更容易避免文件名和代码重复。因为代码变得更轻便了,不需要修改代码本身或改变其模块ID,就可以将它很容易地移动到其他位置。


Developers可以仅仅通过使用AMD优化器在多个环境中运行相同的代码,AMD优化器在CommonJS环境(譬如r.js https://github.com/jrburke/r.js/)下工作。

       define ("myModule",  //定义一个module
            ['foo', 'bar'],
            function (foo, bar) { //模块定义函数,依赖foo  bar 作为参数映射到函数上
                //这里创建你的模块
                var myModule = {
                    dostuff: function () {
                        console.log('yay, stuff');
                    }
                };
                return myModule;
            }
       );
       //另外一种定义方式
       define('myModule', ['math', 'graph'], function (math, graph) {
            return {
                plot: function(x, y) {
                    return graph.drawPie(math.randomGrid(x, y));
                }
            }
       });

require通常用于加载顶级JavaScript文件或模块的代码。

//foo bar是两个外部模块,两个模块加载以后输出作为回调函数的参数传入
require(['foo', 'bar'], function (foo, bar) {
    //
    foo.doSomething();
})

动态加载依赖

define(function (require) {
    var isReady = false, foobar;
    require(['foo', 'bar'], function (foo, bar) {
        isReady = true;
        foobar = foo() + bar();
    });
    return {
        isReady: isReady,
        foobar: foobar
    }
})


了解 AMD: 插件

//使用AMD可以加载任意格式的内容
//这种方式可以用于模板依赖,以便在页面加载的时候进行做换肤方面的工作
define(['./templates', 'text!./template.md', 'css!./template.css'], function (templates, template) {
    console.log(templates);
});


虽然在上面的示例重包含css!用于加载css依赖,但这种方法会有一些警告。党css完全被加载时,它不一定完全生效。取决于如何处理创建过程,它也可能使用css作为一个依赖文件而被包含在优化的文件中,因此,在将css作为加载依赖使用的情况下,一定要谨慎。



该示例可以简单看作是requirejs([‘app/myModule‘], function () {}),表明加载器的顶级全局对象被使用。这里演示了如何使用不同的AMD加载器加载顶级模块nahor,通过使用define()函数,如果塔接受了一个本地模块参数,那么所有require([])的示例都适用于curl.js 和 RequireJS这两种类型的加载器。