js的javascript模块化编程程有哪些方式

& 为什么要模块化:当今,以不再是一个简单的页面,Script也不再是做一些简单的脚本验证,随着WEB.20时代到来,前端面临的必将是越来越庞大的代码,越来越复杂的内部逻辑。&& 从而,团队化的合作开发成为必然,各种工程的引进使得JavaScript的模块化开发成为必然与必须。
& 本文将主要讨论require.js(AMD)以及sea.js(CMD)
&&&&& AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
&&&&& CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
sea.js(CMD)就近依赖: 即在代码运行时,首先是不知道依赖的,需要遍历所有的require关键字,从而找出依赖(使用的正则匹配),与AMD的依赖引入方法相比,确实有其方便之处,但前提是以性能为代价的。& 下面举一个简单的例子,
& 文件目录结构:
--------------------------------------------------------------------------------------------------------------------------------------------------------------
& 在index页面中进行配置入口模块的加载,
当然,对于一些sea.js行为的配置,远远不止这些,有兴趣的同学可以查一下作者的github上的对应部分:Sea.js配置
--------------------------------------------------------------------------------------------------------------------------------------------------------------
模块的搭建:& 可分为:模块定义(define),依赖引入,暴漏
define(function(require, exports, module) {
// 通过 require 引入依赖
//var $ = require('jquery');
//var Spinning = require('./spinning');
// 通过 exports 对外提供接口
exports.doSomething3 = function(){
console.log("do3");
var a = {};
a.doSomething = function(){
console.log("MyOk");
a.doSomething2 = function(){
console.log("MyOk2");
// 或者通过 module.exports 提供整个接口
module.exports =
&&&& 入口的定义其实和模块的定义一样,只是一般不会对外暴漏接口且只负责引入与执行(开启执行),如C中的main函数一样。
require.js(AMD,依赖前置,即在执行当前模块时,我们必须指定当前模块所依赖的模块项,并逐个按循序引入),这样的一种依赖引入模式,相比于CMD,js引擎无需遍历整个工程去找相应的依赖,而是直接引入即可。& 下面以一个require的实例为例,我想读者应该很快就能get it。& 其实
--------------------------------------------------------------------------------------------------------------------------------------------------------------
加载require.js
data-main:就是我们整个模块整体的入口点。
--------------------------------------------------------------------------------------------------------------------------------------------------------------
在main.js中使用require.config()方法,对模块的加载行为进行自定义。
与sea.js类似,baseUrl定义了整个require.js的基础路径,所有模块的引入都将依赖这个路径或者说:。
--------------------------------------------------------------------------------------------------------------------------------------------------------------
重头戏,require.js中的模块的定义:
require是通过define函数的参数中匿名函数前面的一个String数组来我们所要引入的依赖,如此处要使用的car模块,那么就必须将car这个模块的就baseUrl色路径以字符串数组一个元的形式给出,& 与sea.js相比(require('jquery')),确实比较麻烦,但我前面也说过,方便必须是建立在性能代价的基础上. 关于require在软依方面的使用,请移步高人。
其实每种技术的优势都不是绝对的,sea.js也只有其独特魅力,只是作者理解的过于肤浅,我想,只有最合适的业务逻辑,没有最合适的技术。
That&s&& all当前访客身份:游客 [
Things change. Things always change.
:我的唯一的问题是linux软件不熟 不知那些是需要的...
:这是个好东西
:js版hereDoc不错
:高大上,win下有这些工具还是很顺手的
:我觉得怎么读无所谓啊,缩写了以后也可以组成新的...
今日访问:9
昨日访问:76
本周访问:312
本月访问:255
所有访问:26487
JavaScript 模块化编程 - Module Pattern
发表于3年前( 16:38)&&
阅读(4649)&|&评论()
0人收藏此文章,
The Module Pattern,模块模式,也译为模组模式,是一种通用的对代码进行模块化组织与定义的方式。这里所说的模块(Modules),是指实现某特定功能的一组方法和代码。许多现代语言都定义了代码的模块化组织方式,比如 Golang 和 Java,它们都使用 package 与 import 来管理与使用模块,而目前版本的 JavaScript 并未提供一种原生的、语言级别的模块化组织模式,而是将模块化的方法交由开发者来实现。因此,出现了很多种 JavaScript 模块化的实现方式,比如,CommonJS Modules、AMD 等。
以 AMD 为例,该规范使用 define 函数来定义模块。使用 AMD 规范进行模块化编程是很简单的,大致上的结构是这样的:
define(factory(){
// 模块代码
目前尚在制定中的 Harmony/ECMAScript 6(也称为 ES.next),会对模块作出语言级别的定义,但距离实用尚遥不可及,这里暂时不讨论它。
作为一种模式,模块模式其实一直伴随着 JavaScript 存在,与 ES 6 无关。最近我需要重构自己的一些代码,因此我参考和总结了一些实用的模块化编程实践,以便更好的组织我的代码。需要注意的是,本文只是个人的一个总结,比较简单和片面,详尽的内容与剖析请参看文后的参考资料,它们写得很好。本文并不关心模块如何载入,只关心现今该如何组织模块化的代码。还有,不必过于纠结所谓的模式,真正重要的其实还是模块代码及思想。所谓模式,不过是我们书写代码的一些技巧和经验的总结,是一些惯用法,实践中应灵活运用。
## 模块模式
### 闭包与 IIFE (Immediately-Invoked Function Expression)
模块模式使用了 JavaScript 的一个特性,即闭包(Closures)。现今流行的一些 JS 库中经常见到以下形式的代码:
;(function (参数) {
// 模块代码
上面的代码定义了一个匿名函数,并立即调用自己,这叫做自调用匿名函数(SIAF),更准确一点,称为立即调用的函数表达 (Immediately-Invoked Function Expression, IIFE–读做“iffy”)。
在闭包中,可以定义私有变量和函数,外部无法访问它们,从而做到了私有成员的隐藏和隔离。而通过返回对象或函数,或是将某对象作为参数传入,在函数体内对该对象进行操作,就可以公开我们所希望对外暴露的公开的方法与数据。
这,其实就是模块模式的本质。
注1:上面的代码中,最后的一对括号是对匿名函数的调用,因此必不可少。而前面的一对围绕着函数表达式的一对括号并不是必需的,但它可以用来给开发人员一个指示 -- 这是一个 IIFE。也有一些开发者在函数表达式前面加上一个惊叹号(!)或分号(;),而不是用括号包起来。比如 knockoutjs 的源码大致就是这样的:
!function (参数) {
// return something
还有些人喜欢用括号将整个 IIFE 围起来,这样就变成了以下的形式:
(function (参数) {
// return something
注2:在有些人的代码中,将 undefined 作为上面代码中的一个参数,他们那样做是因为 undefined 并不是 JavaScript 的保留字,用户也可以定义它,这样,当判断某个值是否是 undefined 的时候,判断可能会是错误的。将 undefined 作为一个参数传入,是希望代码能按预期那样运行。不过我认为,一般情况下那样做并没太大意义。
### 参数输入
JavaScript 有一个特性叫做隐式全局变量(implied globals),当使用一个变量名时,JavaScript 解释器将反向遍历作用域链来查找变量的声明,如果没有找到,就假定该变量是全局变量。这种特性使得我们可以在闭包里随处引用全局变量,比如 jQuery 或 window。然而,这是一种不好的方式。
考虑模块的独立性和封装,对其它对象的引用应该通过参数来引入。如果模块内需要使用其它全局对象,应该将这些对象作为参数来显式引用它们,而非在模块内直接引用这些对象的名字。以 jQuery 为例,若在参数中没有输入 jQuery 对象就在模块内直接引用 $ 这个对象,是有出错的可能的。正确的方式大致应该是这样的:
;(function (q, w) {
// q is jQuery
// w is window
// 局部变量及代码
})(jQuery, window);
相比隐式全局变量,将引用的对象作为参数,使它们得以和函数内的其它局部变量区分开来。这样做还有个好处,我们可以给那些全局对象起一个别名,比如上例中的 "q"。现在看看你的代码,是否没有经过对 jQuery 的引用就到处都是"$"?
### 模块输出(Module Export)
有时我们不只是要使用全局变量,我们也要声明和输出模块中的对象,这可以通过匿名函数的 return 语句来达成,而这也构成了一个完整的模块模式。来看一个完整的例子:
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
my.moduleProperty = 1;
my.moduleMethod = function () {
这段代码声明了一个变量 MODULE,它带有两个可访问的属性:moduleProperty 和 moduleMethod,其它的代码都封装在闭包中保持着私有状态。参考以前提过的参数输入,我们还可以通过参数引用其它全局变量。
#### 输出简单对象
很多时候我们 return 一个对象作为模块的输出,比如上例就是。
另外,使用对象直接量(Object Literal Notation)来表达 JavaScript 对象是很常见的。比如:var x = { p1: 1, p2: "2", f: function(){ /*... */ } }
很多时候我们都能见到这样的模块化代码:
var Module1 = (function () {
var private_variable = 1;
function private_method() { /*...*/ }
var my = {
property1: 1,
property2: private_variable,
method1: private_method,
method2: function () {
另外,对于简单的模块化代码,若不涉及私有成员等,其实也可以直接使用对象直接量来表达一个模块:
var Widget1 = {
name: "who am i?",
settings: {
call_me: function () {
有一篇文章讲解了这种形式:
不过这只是一种简单的形式,你可以将它看作是模块模式的一种基础的简单表达形式,而把闭包形式看作是对它的一个封装。
#### 输出函数
有时候我们希望返回的并不是一个对象,而是一个函数。有两种需求要求我们返回一个函数,一种情况是我们需要它是一个函数,比如 jQuery,它是一个函数而不是一个简单对象;另一种情况是我们需要的是一个“类”而不是一个直接量,之后我们可以用 "new" 来实例它。目前版本的 JavaScript 并没有专门的“类”定义,但它却可以通过 function 来表达。
var Cat = (function () {
// 私有成员及代码 ...
return function(name) {
this.name =
this.bark = function() { /*...*/ }
var tomcat = new Cat("Tom");
tomcat.bark();
为什么不直接定义一个 function 而要把它放在闭包里呢?简单点的情况,确实不需要使用 IIFE 这种形式,但复杂点的情况,在构造我们所需要的函数或是“类”时,若需要定义一些私有的函数,就有必要使用 IIFE 这种形式了。
另外,在 ECMAScript 第五版中,提出了 Object.create() 方法。这时可以将一个对象视作“类”,并使用 Object.create() 进行实例化,不需使用 "new"。
### Revealing Module Pattern
前面已经提到一种形式是输出对象直接量(Object Literal Notation),而 Revealing Module Pattern 其实就是这种形式,只是做了一些限定。这种模式要求在私有范围内中定义变量和函数,然后返回一个匿名对象,在该对象中指定要公开的成员。参见下面的代码:
var MODULE = (function () {
// 私有变量及函数
var x = 1;
function f1() {}
function f2() {}
public_method1: f1,
public_method2: f2
## 模块模式的变化
上面的举例都是在一个地方定义模块,如果我们需要在数个文件中分别编写一个模块的不同部分该怎么办呢?或者说,如果我们需要对已有的模块作出扩展该怎么办呢?其实也很简单,将模块对象作为参数输入,扩展后再返回自己就可以了。比如:
var MODULE = (function (my) {
my.anotherMethod = function () {
// added method...
}(MODULE));
上面的代码为对象 MODULE 增加了一个 "anotherMethod" 方法。
### 松耦合扩展(Loose Augmentation)
上面的代码要求 MODULE 对象是已经定义过的。如果这个模块的各个组成部分并没有加载顺序要求的话,其实可以允许输入的参数为空对象,那么我们将上例中的参数由 MODULE 改为 MODULE || {} 就可以了:
var MODULE = (function (my) {
// add capabilities...
}(MODULE || {}));
### 紧耦合扩展(Tight Augmentation)
与上例不同,有时我们要求在扩展时调用以前已被定义的方法,这也有可能被用于覆盖已有的方法。这时,对模块的定义顺序是有要求的。
var MODULE = (function (my) {
var old_moduleMethod = my.moduleM
my.moduleMethod = function () {
// 方法重载
// 可通过 old_moduleMethod 调用以前的方法...
}(MODULE));
### 克隆与继承(Cloning and Inheritance)
var MODULE_TWO = (function (old) {
var my = {},
for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
var super_moduleMethod = old.moduleM
my.moduleMethod = function () {
// override method on the clone, access to super through super_moduleMethod
}(MODULE));
有时我们需要复制和继承原对象,上面的代码演示了这种操作,但未必完美。如果你可以使用 Object.create() 的话,请使用 Object.create() 来改写上面的代码:
var MODULE_TWO = (function (old) {
var my = Object.create(old);
var super_moduleMethod = old.moduleM
my.moduleMethod = function () {
// override method ...
}(MODULE));
### 子模块(Sub-modules)
模块对象当然可以再包含子模块,形如 MODULE.Sub=(function(){}()) 之类,这里不再展开叙述了。
### 各种形式的混合
以上介绍了常见的几种模块化形式,实际应用中有可能是这些形式的混合体。比如:
var UTIL = (function (parent, $) {
var my = parent.ajax = parent.ajax || {};
my.get = function (url, params, callback) {
// ok, so I'm cheating a bit :)
return $.getJSON(url, params, callback);
}(UTIL || {}, jQuery));
## 与其它模块规范或 JS 库的适配
### 模块环境探测
现今,CommonJS Modules 与 AMD 有着广泛的应用,如果确定 AMD 的 define 是可用的,我们当然可以使用 define 来编写模块化的代码。然而,我们不能假定我们的代码必然运行于 AMD 环境下。有没有办法可以让我们的代码既兼容于 CommonJS Modules 或 AMD 规范,又能在一般环境下运行呢?
其实我们只需要在某个地方加上对 CommonJS Modules 与 AMD 的探测并根据探测结果来“注册”自己就可以了,以上那些模块模式仍然有用。
AMD 定义了 define 函数,我们可以使用 typeof 探测该函数是否已定义。若要更严格一点,可以继续判断 define.amd 是否有定义。另外,SeaJS 也使用了 define 函数,但和 AMD 的 define 又不太一样。
对于 CommonJS,可以检查 exports 或是 module.exports 是否有定义。
现在,我写一个比较直白的例子来展示这个过程:
var MODULE = (function () {
var my = {};
// 代码 ...
if (typeof define == 'function') {
define( function(){ } );
}else if (typeof module != 'undefined' && module.exports) {
module.exports =
上面的代码在返回 my 对象之前,先检测自己是否是运行在 AMD 环境之中(检测 define 函数是否有定义),如果是,就使用 define 来定义模块,否则,继续检测是否运行于 CommonJS 中,比如 NodeJS,如果是,则将 my 赋值给 module.exports。因此,这段代码应该可以同时运行于 AMD、CommonJS 以及一般的环境之中。另外,我们的这种写法应该也可在 SeaJS 中正确执行。
### 其它一些 JS 库的做法
现在许多 JS 库都加入了对 AMD 或 CommonJS Modules 的适应,比如 jQuery, Mustache, doT, Juicer 等。
jQuery 的写法可参考 exports.js:
if ( typeof module === "object" && module && typeof module.exports === "object" ) {
module.exports = jQ
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function () { return jQ } );
if ( typeof window === "object" && typeof window.document === "object" ) {
window.jQuery = window.$ = jQ
与前面我写的那段代码有些不同,在对 AMD 和 CommonJS 探测之后,它将 jQuery 注册成了 window 对象的成员。
然而,jQuery 是一个浏览器端的 JS 库,它那样写当然没问题。但如果我们所写的是一个通用的库,就不应使用 window 对象了,而应该使用全局对象,而这一般可以使用 this 来得到。
我们看看 Mustache 是怎么做的:
(function (root, factory) {
if (typeof exports === "object" && exports) {
factory(exports); // CommonJS
var mustache = {};
factory(mustache);
if (typeof define === "function" && define.amd) {
define(mustache); // AMD
root.Mustache = // &script&
}(this, function (mustache) {
// 模块主要的代码放在这儿
这段代码与前面介绍的方式不太一样,它使用了两个匿名函数。后面那个函数可以看作是模块代码的工厂函数,它是模块的主体部分。前面那个函数对运行环境进行检测,根据检测的结果对模块的工厂函数进行调用。另外,作为一个通用库,它并没使用 window 对象,而是使用了 this,因为在简单的函数调用中,this 其实就是全局对象。
再看看 doT 的做法。doT 的做法与 Mustache 不同,而是更接近于我在前面介绍 AMD 环境探测的那段代码:
(function() {
"use strict";
var doT = {
version: '1.0.0',
templateSettings: { /*...*/ },
template: undefined, //fn, compile template
//fn, for express
if (typeof module !== 'undefined' && module.exports) {
module.exports = doT;
} else if (typeof define === 'function' && define.amd) {
define(function(){return doT;});
(function(){ return this || (0,eval)('this'); }()).doT = doT;
这段代码里的 (0, eval)('this') 是一个小技巧,这个表达式用来得到 Global 对象,'this' 其实是传递给 eval 的参数,但由于 eval 是经由 (0, eval) 这个表达式间接得到的,因此 eval 将会在全局对象作用域中查找 this,结果得到的是全局对象。若是代码运行于浏览器中,那么得到的其实是 window 对象。这里有一个针对它的讨论:
其实也有其它办法来获取全局对象的,比如,使用函数的 call 或 apply,但不给参数,或是传入 null:
var global_object = (function(){ }).call();
你可以参考这篇文章:
Juicer 则没有检测 AMD,它使用了如下的语句来检测 CommonJS Modules:
typeof(module) !== 'undefined' && module.exports ? module.exports = juicer : this.juicer =
另外,你还可以参考一下这个:
(function (root, Library) {
// The square bracket notation is used to avoid property munging by the Closure Compiler.
if (typeof define == "function" && typeof define["amd"] == "object" && define["amd"]) {
// Export for asynchronous module loaders (e.g., RequireJS, `curl.js`).
define(["exports"], Library);
// Export for CommonJS environments, web browsers, and JavaScript engines.
Library = Library(typeof exports == "object" && exports || (root["Library"] = {
"noConflict": (function (original) {
function noConflict() {
root["Library"] =
// `noConflict` can't be invoked more than once.
delete Library.noC
return noC
})(root["Library"])
})(this, function (exports) {
我觉得这个写得有些复杂了,我也未必需要我的库带有 noConflict 方法。不过,它也可以是个不错的参考。
## JavaScript 模块化的未来
未来的模块化方案会是什么样的?我不知道,但不管将来如何演化,作为一种模式,模块模式是不会过时和消失的。
如前所述,尚在制定中的 ES 6 会对模块作出语言级别的定义。我们来看一个实例,以下的代码段摘自“”:
module Car {
// 内部变量
var licensePlateNo = '556-343';
// 暴露到外部的变量和函数
export function drive(speed, direction) {
console.log('details:', speed, direction);
export module engine{
export function check() { }
export var miles = 5000;
export var color = 'silver';
我不知道 ES 6 将来会否对此作出改变,对上面的这种代码形式,不同的人会有不同的看法。就我个人而言,我十分不喜欢这种形式!
确实,我们可能需要有一种统一的模块化定义方式。发明 AMD 和 RequireJS 的人也说过 AMD 和 RequireJS 应该被淘汰了,运行环境应该提供模块的原生支持。然而,ES 6 中的模块定义是否是正确的?它是否是一个好的解决方案呢?我不知道,但我个人真的很不喜欢那种方式。很多人十分喜欢把其它语言的一些东西生搬硬套到 JavaScript 中,或是孜孜不倦地要把 JavaScript 变成另外一种语言,我相当讨厌这种行为。我并非一个保守的人,我乐意接受新概念、新语法,只要它是好的。但是,ES 6 草案中的模块规范是我不喜欢的,起码,我认为它脱离了现实,否定了开源社区的实践和经验,是一种意淫出来的东西,这使得它在目前不能解决任何实际问题,反而是来添乱的。
按目前的 ES6 草案所给出的模块化规范,它并没有采用既有的 CommonJS Modules 和 AMD 规范,而是定义了一种新的规范,而且这种规范修改了 JavaScript 既有的语法形式,使得它没有办法像 ES5 中的 Object.create、Array.forEach 那样可以利用现有版本的 JavaScript 编写一些代码来实现它。这也使得 ES 6 的模块化语法将在一段时期内处于不可用的状态。
引入新的语法也不算是问题,然而,为了模块而大费周折引出那么多新的语法和定义,真的是一种好的选择么?话说,它解决了什么实质性的问题而非如此不可?现今流行的 AMD 其实简单到只定义了一个 "define" 函数,它有什么重大问题?就算那些专家因种种原因或目的而无法接受 AMD 或其它开源社区的方案,稍作出一些修改和中和总是可以的吧,非要把 JavaScript 改头换面不可么?确实有人写了一些观点来解释为何不用 AMD,然而,那些解释和观点其实大都站不住脚。比如说,其中一个解释是 AMD 规范不兼容于 ES 6!可笑不可笑?ES 6 尚未正式推出,完全实现了 ES 6 的 JavaScript 运行时也没几个,而 AMD 在开源社区中早已十分流行,这个时候说 AMD 不兼容 ES 6,我不知道这是什么意思。
就我看来,现今各种形形色色的所谓标准化工作组,很多时候像是高高在上的神仙,他们拉不下脸全身心地参与到开源社区之中,他们就是要作出与开源社区不同的规范,以此来彰显他们的工作、专业与权威。而且,很多时候他们过于官僚,又或者夹杂在各大商业集团之间举棋不定。我不否认他们工作的重要性,然而,以专家自居而脱离或否定开源社区的实践,以及商业与政治的利益均衡等,使得他们的工作与开源社区相比,在技术的推动与发展上成效不足甚至添乱。
回到 ES 6 中的模块,想想看,我需要修改我的代码,在其中加上诸如 module, export, import 之类的新的语法,修改之后的代码却没办法在现今版本的 JavaScript 中运行,而且,与现今流行的模块化方案相比,这些工作也没什么实质性的帮助,想想这些,我只感觉像是吃了一个苍蝇。
ES 6 的发展当然不会因为我的吐嘈而有任何变化,我也不愿再展开讨论。未来的模块化方案具体是什么样的无法知晓,但起码我可以得到以下的结论:
模块模式不会过时
ES 6 不会接纳 AMD 等现有方案,但不管如何,JavaScript 将会有语言级别的模块定义
ES 6 中的模块在一段时期内是不可用的
即使 ES 6 已达到实用阶段,现今的模块化方案仍会存在和发展
## 参考资料
版权声明:自由转载-非商用-非衍生-保持署名 |
更多开发者职位上
1)">1)">1" ng-class="{current:{{currentPage==page}}}" ng-repeat="page in pages"><li class='page' ng-if="(endIndex<li class='page next' ng-if="(currentPage
相关文章阅读AngularJS模块化编程最佳实践(Modular Programming Best Practices) - 简书
下载简书移动应用
写了107815字,被12人关注,获得了32个喜欢
AngularJS模块化编程最佳实践(Modular Programming Best Practices)
这篇文章我是在《angularjs新手到忍者》(《AngularJS_ Novice to Ninja》)这本书看到的,是讲angularjs如何模块化的,讲的很不错,但是翻译水平有限,望大家批评指正。同时我也把这篇文章放进了github,下面是连接。当你把你的项目源码分为不同的模块的时候,一般由两个选择: (1)通过层来实现模块化(2)通过特征来实现模块化 首先我们进入angular seed项目,下面是这个项目在github上的地址,这是一个不错的angular项目,大家可以学习一下。( 文件的app/js文件中,看看采用的哪种模式,当你打开文件夹,你会看到如下几个文件:
2、controller.js
3、directive.js
4、filter.js
5、server.js
这就是通过层的概念来实现的模块化,每一种组件的类型,被装进了一种特殊的模块。最终这个主要的依赖于其他四个模块的入口app模块在app.js模块中定义。这是通过angular.module()的第二个参数来指定的。你只需要参考在html中ng-app指令。这种类型模块化在很多场景都很有用。例如当你遇到一个特殊类型的bug,找到服务,你就指定在哪里发现。但是当你的app应用规模和复杂性增长到一定程度,或许就适用于通过层来划分模块的方式。可以通过特征的方式来实现。例如你的站点需要一个登陆模块。所有这些模块都独立存在,并且紧密的耦合在一起。通常你为每个模块创建一个独立的文件用来放置相关的JavaScript文件在每个相关的文件夹中。这些文件夹中的代码是可重用的,因为你能把某一个模块的一整个文件夹放入另外一个不同的项目中。并且不同的团队之间可以同时开发不同的模块,这些模块并没有紧密的耦合在一起。此外,单元测试也就变得小菜一碟了,只要你加载需要的模块,并且分开测试也变得容易。我们调整一下Angular Seed Project来使用这种方式,例如博客系统,可以使用这种模式:结构如下:
/img -- application level images
/css -- application level css
app.js -- the main app module
controllers.js --controllers for login module
directives.js --directives for login module
/views -- views for login module
loginModule.js -- Main login module definition
controllers.js --controllers for login module
directives.js --directives for login module
/views -- views for comment module
commentModule.js -- Main comment module definition
index.html
在这些的文件中我们定义自己的模块。比如登陆模块,如下
app/modules/login/js/controller
angular.module('mainApp.login.controller',[]);
app/modules/login/js/directive.js
angular.module('mainApp.login.directives',[])
app/modules/login/loginModule.js
angular.module('loginModule',['mainApp.login.controller','mainApp.login.directives'])
对于评论模块,定义如下
/app/modules/comment/js/controllers.js
angular.module('ment.controllers',[]);
/app/modules/comment/js/directives.js
angular.module('ment.directives',[]);
/app/modules/comment/loginModule.js
angular.module('commentModule',['ment.controllers',ment.directives']);
在主要的模块中定义/app/app.js如下
angular.module('mainApp',['loginModule','commentModule'])
最终在index.html我们启动文件通过写入
ng-app='mainApp'
正如你看到的,这个登陆模块loginModule和评论模块commentModule互相是不通信的。但是通过mainApp模块组合在一起。在HTML文件中,当angular遇到ng-app,它就通过加载指定的模块启动。在这种情况下,angular启动app程序通过加载mainApp模块。但是angular发现这个mainApp模块依赖于另外两个模块loginModule和commentModule。但是这两个模块本身也依赖于其他两个模块(控制器模块和指令模块),也需要angular来加载。这样angular启动程序通过加载需要的模块。
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:}

我要回帖

更多关于 javascript模块化编程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信