模块化JavaScript设计模式(一)
在可扩展JavaScript的世界里,假设我们说一个应用程序是模块化(modular)的,那么通常意味着它是由一系列存储于模块中的高度解耦,不同的功能片段组成。在可能的情况下,通过一处依赖性,松耦合能够使应用程序的可维护性更加简单。 假设有效地实现了这点,就非常easy地了解一部分怎样影响还有一个部分。
异步模块定义(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,以便更easy避免文件名称和代码反复。由于代码变得更轻便了,不须要改动代码本身或改变其模块ID,就能够将它非常easy地移动到其它位置。
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能够载入随意格式的内容 //这样的方式能够用于模板依赖,以便在页面载入的时候进行做换肤方面的工作 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这两种类型的载入器。