模块模式
道格拉斯所说的模块模式则是为单例创建私有私有变量和特权方法。所谓单例,指的就是只有一个实例的对象。按照惯例,JavaScript是以对象字面量的方式来创建单列对象的。
var singleton = { name: value, method: function() { } }
模块模式通过为单例添加私有变量和特权方法能够使其得到增强,其语法形式如下:
var singleton = function() { var privateVariable = 10; function privateFunction() { return false; } return { publicVariable: true, publicMethod: function() { privateVariable++; return privateFunction(); } } }();
这个模块模式使用了一个返回对象的匿名函数。在这个匿名函数内部,首先定义了私有变量和函数。然后,将一个对象字面量作为函数的值返回。返回的对象字面量中只包含可以公开的属性和方法。由于这个对象是在匿名函数内部定义的,因此它的公有方法有权访问私有变量和函数 。从本质上来讲,这个对象字面量定义的是单例的公共接口。这种模式在需要对单例进行某些初始化,同事又需要维护其私有变量时是非常有用的,例如:
var application = function() { var components = new Array(); components.push(new BaseComponenet()); return { getComponentCount: function() { return components.length; }, registerComponenet: function(component) { if (typeof component == "object") { components.push(component); } } }; }();
在Web应用程序中,经常需要使用一个单例来管理应用程序的信息。这个简单的例子创建了一个用于管理组件的application对象。在创建这个对象的过程中,首先声明一个私有的components数组,并向数组中添加了一个BaseComponent的新实例。而返回对象的getComponentCount() 和 registerComponent()方法,都是有权访问数据components的特权方法。前者只是返回已注册的组件数目,后者用于注册新组件。
简言之,如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法,那么就可以使用模块模式。以这种模式创建的每个单例都是Object的实例,因为最终要通过一个对象字面量来表示它。事实上,这也没有什么;毕竟,单例通常都是作为全局对象存在的,我们不会将它传递个一个函数。因此,也就没有什么必要使用instanceof操作符来检查其对象类型了。
增强的模块模式
有人进一步改进了模块模式,即在返回对象之前加入对其增强的代码。这种增强的模块模式适合那些单例必须是某种类型的实例,同事还必须添加某些属性和(或)方法对其加以增强的情况。看下面的例子:
var singleton = function() { var components = new Array(); function privateFunction() { return false; } var object = new CustomType(); object.publicProperty = true; object.publicMethod = function() { privateVariable++; return privateFunction(); } return object; }();
如果前面演示模块模式的例子中的application对象必须是BaseComponent的实例,那么可以使用以下代码:
var application = function() { var components = new Array(); components.push(new BaseComponent()); var app = new BaseComponent(); app.getComponentCount = function() { return components.length; }; app.registerComponent = function(component) { if (typeof component == "object") { components.push(component); } }; return app; }();
在这个重写后的应用程序单例中,首先也是像前面例子中一样定义了私有变量。主要的不同之处在于命名变量的app的创建过程,因为它必须是BaseComponent的实例。这个实例实际上是application对象的局部变量版。此后,我们又为app对象添加了能够访问私有变量的方法。最后一步是返回app对象,结果仍然是将它赋值给全局变量application。
备注: 摘取自《JAVASCRIPT高级程序设计:第3版》