Module (模块)模式
模块是任何强大应用程序架构中不可缺少的一部分,它通常能够帮助我们清晰地分离和组织项目中的代码单元。
在 Javascript 中,有几种用于实现模块的方法,包括:
- 对象字面量表示法
对象字面量是对象定义的一种简要形式,目的在于简化创建包含大量属性的对象的过程。
- Module 模式
Module 模式在某种程度上是基于对象字面量
- AMD 模块
- CommonJS 模块
- ECMAScript Harmony 模块
对象字面量
在对象字面量表示法中,一个对象被描述为一组包含在大括号 {} 中、以逗号分隔的 name/value 对。对象内的名称可以是字符串或标识符,后面跟着一个冒号。
1 | var myObectLiteral = { |
下面是一个更完整的实例,使用对象字面量表示法定义的模板
1 | var myModule = { |
Module(模块)模式
Module 模式最初被定义为一种在传统软件工程中为类提供私有和公有封装的方法。
在 javaScript 中,Module 模式用于进一步模拟类的概念,通过这种方式,能够使一个单独的对象拥有公有/私有方法和变量,从而屏蔽来自全局作用域的特殊部分。
私有
Module 模式使用闭包封装“私有”状态和组织。它提供了一种包装混合公有/私有方法和变量的方式,防止其泄漏至全局作用域,并与别的开发人员的接口发生冲突。通过该模式,只需返回一个公有的 API, 而其他的一切都维持在私有的闭包里。
该模式除了返回一个对象而不是一个函数之外,非常类似于一个立即调用的函数表达式。
示例
这里通过创建一个自包含的模块来实现 Module 模式。
1 | var testModule = (function(){ |
使用Module模式时,可能会觉得它可以用来定义一个简单的模板来入门使用。下面是一个包含命名空间、公有和私有变量的Module模式:
1 | var myNamespace = (function(){ |
使用这种模式实现的购物车。模块本身是完全自包含在一个被称为baskeModule的全局变量中。
1 | var baskeModule = (function(){ |
请注意上面的basket模块中的作用域函数是如何包裹在所有函数的周围,然后调用并立即存储返回值。这有很多优点,包括;
- 只有我们的模块才能享有拥有私有函数的自由。因为它们不会暴露于页面的其余部分(只会暴露我们输出的API),我们认为它们是真正的私有。
- 鉴于函数往往已声明并命名,在视图找到有哪些函数抛出异常时,这将使得在调试器中显示调用堆栈变得更容易。
- 它还可以让我们返回不同的函数。开发人员可以使用它来执行UA测试,从而针对IE在它们的模块内提供一个代码路径,但我们现在可以很容易地选择特征检测来实现类似的目的。
Module 模式变化
模式的这种变化演示了全局变量(如:jQuery,Underscore)如何作为参数传递给模块化的匿名函数。这允许我们引入它们,并按照我们所希望的为它们取个本地别名。
1 | // 全局模块 |
引出
下一个变化允许我们声明全局变量,而不需实现它们,并可以同样地支持上一个示例中的全局引入的概念。
1 | var myModule = (function(){ |
工具包和特定框架的Module模式实现
Dojo, 提供了一种和对象一起用的便利方法 dojo.setObject().其第一个参数是用点号分割的字符串,如 myObj.parent.child
,它在parent对象中引用一个称为child的属性,parent对象是在myObj内部定义。我们可以使用 setObject() 设置子级的值(比如属性等),如果中间对象不存在的话,也可以通过点号分割将中间的字符串作为中间对象进行创建。
例如,如果要将basket.score声明为store名称空间的对象,可以采用传统的方法来实现。
1 | var store = window || {}; |
// 使用Dojo(AMD兼容的版本)和上述方法,如下所示:
dojo.setObject的信息
1 | require(["dojo/_base/customStore"], function(store) { |
ExtJS
Sencha ExtJS
演示了EXTJS框架如何正确使用Module模式
这里是一个示例;如何定义一个名称空间,然后填充一个包含私有和公有API的模块。
1 |
|
YUI
在使用YUI构建应用程序时,我们也可以实现Module模式
1 | Y.nameSpace("store.basket") = (function() { |
jQuery
下面的示例中,定义了library函数,它声明一个新库,并在创建新库(即模块)时将init函数自动绑定到document.ready
1 | function library(module) { |