即时函数
在上一篇中,我们搭起了一个简单的模块架子,但是在通常的场景下,我们会遇到一些问题,实例如下:
//定义一个全局标识
var GLOBAL = GLOBAL || {};
//处理命名空间的函数
GLOBAL.namespace = function(str) {
var arr = str.split("."),
o = GLOBAL;
for (i = (arr[0] == "GLOBAL") ? 1 : 0; i < arr.length; i++) {
o[arr[i]] = o[arr[i]] || {};
o = o[arr[i]];
}
}
//注册一个模块
GLOBAL.namespace("Module");
//字面量方式
GLOBAL.Module.console = {
msg : "WeiRan",
log : function(){
console.log(this.msg);
}
}
GLOBAL.Module.console.log(); //WeiRan
console.log(GLOBAL.Module.console.msg); //WeiRan
//即时函数方式
GLOBAL.Module.console1 = (function(){
var msg = "WeiRan";
return{
log : function(){
console.log(msg);
}
}
}());
GLOBAL.Module.console1.log(); //WeiRan
console.log(GLOBAL.Module.console1.msg); //undefined
在上面我列举了两种编写模块的方式,第一种字面量的形式完全不能保证私有属性,他的所有成员都是公开的,第二种,我们通过即时函数提供的私有作用域保证了模块私有成员的私有性,在最后返回对象了一个对象,该对象包含该模块的公共API。
而对于返回的对象,如果我们还要对公共API的具体实现逻辑也保持私有,那么使用揭示模块模式就再合适不过了。
揭示模块模式
揭示模块模式是对模块模式中私有性保护的升级,就拿我以前的一段代码为例,详细代码如下:
GLOBAL.comm.comnav = (function() {
var bindNav = function(navList) {
$.each(navList, function(key, val) {
$("#" + val.split("-")[0] + ">span").click(function() {
$(this).siblings().each(function() {
$(this).find(".active").hide().siblings().find("[_tag=" + $(this).attr("_tag") + "]").removeClass("red");
});
$(this).find(".active").show().siblings().find("[_tag=" + $(this).attr("_tag") + "]").addClass("red");
showTag([val.split("-")[1], val.split("-")[2]], $(this).attr("_tag"));
});
});
};
var processNav = function(navId, commId, listId) {
return navId + "-" + commId + "-" + listId;
};
var showTag = function(tagList, tagName) {
$.each(tagList, function(index) {
$("#" + tagList[index]).find("[_tag=" + tagName + "]").show().siblings().hide();
});
};
return {
init: bindNav,
newInstantce: processNav
}
})();
在上面的示例中,我在模块内部定义了三个私有方法(注意是以函数表达式的形式定义的),我没有把API函数的具体逻辑显式的写在返回的对象中,我是以函数名的方式传递了一个私有方法的引用给API函数,这样我们就连模块暴露的API方法都进行了处理,这样才算真正的接口(只有声明,没有实现)
结语
这篇总结了下模块创建的方式,如果你在文中发现错误或则你觉得不正确的地方,希望你的指正。