module模式是一个比较流行的设计模式,它可以通过大括号封装私有的变量,方法,状态的,通过包装这些内容,一般全局的对象不能直接访问,在这个设计模式里,只返回一个API,其它的内容全部被封装成私有的了。
另外,这个模式和自执行的函数表达式比较相似,唯一的不同是module返回的是对象,而自执行函数表达式返回的是function。
众所周知, JavaScript不想其它语言一样有访问修饰符,不能为每个字段或者方法声明private,public修饰符,那这个模式我们是如何实现的呢?那就是return一个对象,里面包括一些公开的方法,这些方法有能力去调用内部的对象。
看一下,下面的代码,这段代码是一个自执行代码,声明里包括了一个全局的对象basketModule, basket数组是一个私有的,所以你的整个程序是不能访问这个私有数组的,同时我们return了一个对象,其内包含了3个方法(例如addItem,getItemCount,getTotal),这3个方法可以访问私有的basket数组。
var basketModule = (function() { var basket = []; //private return { //exposed to public addItem: function(values) { basket.push(values); }, getItemCount: function() { return basket.length; }, getTotal: function(){ var q = this.getItemCount(),p=0; while(q--){ p+= basket[q].price; } return p; } } }());
同时注意,我们return的对象直接赋值给了basketModule,所以我们可以像下面一样使用:
//basketModule is an object with properties which can also be methods basketModule.addItem({item:'bread',price:0.5}); basketModule.addItem({item:'butter',price:0.3}); console.log(basketModule.getItemCount()); console.log(basketModule.getTotal()); //however, the following will not work: console.log(basketModule.basket);// (undefined as not inside the returned object) console.log(basket); //(only exists within the scope of the closure)
那在各个流行的类库(如Dojo, jQuery)里是如何来做呢?
Dojo
Dojo试图使用dojo.declare来提供class风格的声明方式,我们可以利用它来实现Module模式,例如如果你想再store命名空间下声明basket对象,那么可以这么做:
//traditional way var store = window.store || {}; store.basket = store.basket || {}; //using dojo.setObject dojo.setObject("store.basket.object", (function() { var basket = []; function privateMethod() { console.log(basket); } return { publicMethod: function(){ privateMethod(); } }; }()));
结合dojo.provide一起来使用,非常强大。
YUI
下面的代码是YUI原始的实现方式:
YAHOO.store.basket = function () { //"private" variables: var myPrivateVar = "I can be accessed only within YAHOO.store.basket ."; //"private" method: var myPrivateMethod = function () { YAHOO.log("I can be accessed only from within YAHOO.store.basket"); } return { myPublicProperty: "I'm a public property.", myPublicMethod: function () { YAHOO.log("I'm a public method."); //Within basket, I can access "private" vars and methods: YAHOO.log(myPrivateVar); YAHOO.log(myPrivateMethod()); //The native scope of myPublicMethod is store so we can //access public members using "this": YAHOO.log(this.myPublicProperty); } }; } ();
jQuery
jQuery里有很多Module模式的实现,我们来看一个不同的例子,一个library函数声明了一个新的library,然后创建该library的时候,在document.ready里自动执行init方法。
function library(module) { $(function() { if (module.init) { module.init(); } }); return module; } var myLibrary = library(function() { return { init: function() { /*implementation*/ } }; }());
对象自面量
对象自面量使用大括号声明,并且使用的时候不需要使用new关键字,如果对一个模块里的属性字段的publice/private不是很在意的话,可以使用这种方式,不过请注意这种方式和JSON的不同。对象自面量:var item={name: "tom", value:123} JSON:var item={"name":"tom", "value":123}。
var myModule = { myProperty: 'someValue', //object literals can contain properties and methods. //here, another object is defined for configuration //purposes: myConfig: { useCaching: true, language: 'en' }, //a very basic method myMethod: function () { console.log('I can haz functionality?'); }, //output a value based on current configuration myMethod2: function () { console.log('Caching is:' + (this.myConfig.useCaching) ? 'enabled' : 'disabled'); }, //override the current configuration myMethod3: function (newConfig) { if (typeof newConfig == 'object') { this.myConfig = newConfig; console.log(this.myConfig.language); } } }; myModule.myMethod(); //I can haz functionality myModule.myMethod2(); //outputs enabled myModule.myMethod3({ language: 'fr', useCaching: false }); //fr
CommonJS