简介
Module模式是JavaScript编程中一个非常通用的模
首先我们来看看Module模式的基本特征:
- 模块化,可重用
- 封装了变量和function,
和全局的namaspace不接触,松耦合 - 只暴露可用public的方法,其它私有方法全部隐藏
关于Module模式,最早是由YUI的成员Eric Miraglia在4年前提出了这个概念,
基本用法
先看一下最简单的一个实现,代码如下:
var Calculator = function (eq) { //这里可以声明私有成员 var eqCtl = document.getElementById(eq); return { // 暴露公开的成员 add: function (x, y) { var val = x + y; eqCtl.innerHTML = val; } }; };
我们可以通过如下的方式来调用:
var calculator = new Calculator('eq'); calculator.add(2, 2);
大家可能看到了,每次用的时候都要new一下,
匿名闭包
匿名闭包是让一切成为可能的基础,
(function () { // ... 所有的变量和function都在这里声明,并且作用域也只能在这个匿名闭包里 // ...但是这里的代码依然可以访问外部全局的对象 }());
注意,匿名函数后面的括号,
(function () {/* 内部代码 */})();
不过我们推荐使用第一种方式,关于函数自执行,
引用全局变量
JavaScript有一个特性叫做隐式全局变量,
不过,好在在匿名函数里我们可以提供一个比较简单的替代方案,
(function ($, YAHOO) { // 这里,我们的代码就可以使用全局的jQuery对象了,YAHOO也是一样 } (jQuery, YAHOO));
现在很多类库里都有这种使用方式,比如jQuery源码。
不过,有时候可能不仅仅要使用全局变量,而是也想声明全局变量,
var blogModule = (function () { var my = {}, privateName = "博客园"; function privateAddTopic(data) { // 这里是内部处理代码 } my.Name = privateName; my.AddTopic = function (data) { privateAddTopic(data); }; return my; } ());
上面的代码声明了一个全局变量blogModule,
高级用法
上面的内容对大多数用户已经很足够了,
扩展
Module模式的一个限制就是所有的代码都要写在一个文件,
var blogModule = (function (my) { my.AddPhoto = function () { //添加内部代码 }; return my; } (blogModule));
这段代码,看起来是不是有C#里扩展方法的感觉?有点类似,
松耦合扩展
上面的代码尽管可以执行,但是必须先声明blogModule,
var cnblogs = cnblogs || {} ;
这是确保cnblogs对象,在存在的时候直接用,
var blogModule = (function (my) { // 添加一些功能 return my; } (blogModule || {}));
通过这样的代码,每个单独分离的文件都保证这个结构,
紧耦合扩展
虽然松耦合扩展很牛叉了,但是可能也会存在一些限制,
var blogModule = (function (my) { var oldAddPhotoMethod = my.AddPhoto; my.AddPhoto = function () { // 重载方法,依然可通过oldAddPhotoMethod调用旧的方法 }; return my; } (blogModule));
通过这种方式,我们达到了重载(我感觉是覆盖,不是重载)的目的
克隆与继承
var blogModule = (function (old) { var my = {}, key; for (key in old) { if (old.hasOwnProperty(key)) { my[key] = old[key]; } } var oldAddPhotoMethod = old.AddPhoto; my.AddPhoto = function () { // 克隆以后,进行了重写,当然也可以继续调用oldAddPhotoMethod }; return my; } (blogModule));
这种方式灵活是灵活,但是也需要花费灵活的代价,
跨文件共享私有对象
通过上面的例子,我们知道,
var blogModule = (function (my) { var _private = my._private = my._private || {}, _seal = my._seal = my._seal || function () { delete my._private; delete my._seal; delete my._unseal; }, _unseal = my._unseal = my._unseal || function () { my._private = _private; my._seal = _seal; my._unseal = _unseal; }; return my; } (blogModule || {}));
任何文件都可以对他们的局部变量_private设属性,
子模块
最后一个也是最简单的使用方式,那就是创建子模块(
blogModule.CommentSubModule = (function () { var my = {}; // ... return my; } ());
尽管非常简单,我还是把它放进来了,
总结
上面的大部分方式都可以互相组合使用的,
参考文章:
http://yuiblog.com/blog/2007/
http://www.adequatelygood.com/