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
关于 commonjs的介绍,这里就不多说了,之前很多文章都有介绍,我们这里要提一下的是commonjs标准里里有2个重要的参数exports和require,exports是代表要加载的模块,require是代表这些加载的模块需要依赖其它的模块,也需要将它加载进来。
/*
example of achieving compatibility with amd and standard commonjs by putting boilerplate around the standard commonjs module format:
*/
(function(define){
define(function(require,exports){
// module contents
var dep1 = require("dep1");
exports.someexportedfunction = function(){...};
//...
});
})(typeof define=="function"?define:function(factory){factory(require,exports)});
有很多commonjs标准的模块加载实现,我比较喜欢的是requirejs,它能否非常好的加载模块以及相关的依赖模块,来一个简单的例子,例如需要将图片转化成ascii码,我们先加载encoder模块,然后获取他的encodetoascii方法,理论上代码应该是如下:
var encodetoascii = require("encoder").encodetoascii;
exports.encodesomesource = function(){
//其它操作以后,然后调用encodetoascii
}
但是上述代码并没用工作,因为encodetoascii函数并没用附加到window对象上,所以不能使用,改进以后的代码需要这样才行:
define(function(require, exports, module) {
var encodetoascii = require("encoder").encodetoascii;
exports.encodesomesource = function(){
//process then call encodetoascii
}
});
以上就是javascript架构设计module模式用法实例详解的详细内容。