JavaScript模块模式详解:基于YUI的私有与公共成员实现
本文深入解析Douglas Crockford提出的JavaScript模块模式,结合YUI库演示如何通过命名空间对象和匿名函数立即执行实现单例。重点阐述利用闭包机制保护私有变量与方法,同时暴露公共API,从而避免全局命名空间污染并提升代码可维护性。
JavaScript模块模式概述
Douglas Crockford提出了一种实现单例模式的实用方案,该模式对于基于YUI构建的应用程序具有显著价值。Douglas将其称为模块模式(module pattern),其工作原理如下:
命名空间与公共成员定义
首先创建命名空间对象。若使用YUI,可调用YAHOO.namespace()方法,例如执行YAHOO.namespace("myProject");。此操作会分配一个空的myProject对象作为YAHOO的成员(若myProject已存在则不覆盖)。随后,即可向YAHOO.myProject添加成员。
接下来,将匿名函数的返回值分配给命名空间对象:
YAHOO.myProject.myModule = function () {
return {
myPublicProperty: "我作为YAHOO.myProject.myModule.myPublicProperty被访问。";
myPublicMethod: function () {
YAHOO.log("我作为YAHOO.myProject.myModule.myPublicMethod被访问。");
}
};
}(); // 这个括号导致匿名函数被执行且返回
注意最后一行包含闭合大括号及紧随其后的括号(),这种语法结构触发了匿名函数的立即执行,并返回包含myPublicProperty和myPublicMethod的对象。一旦匿名函数返回,该对象即作为YAHOO.myProject.myModule被访问。
利用闭包实现私有成员
在匿名函数内部、返回语句之前添加“私有”方法和变量。此前仅将myPublicProperty和myPublicMethod直接分配给YAHOO.myProject.myModule。此外,当在返回语句前放置代码时,该模式还支持增加的效用。
YAHOO.myProject.myModule = function () {
//“私有”变量:
var myPrivateVar = “我仅能在YAHOO.myProject.myModule内被访问。”;
//私有方法:
var myPrivateMethod = function () {
YAHOO.log(”我仅能在YAHOO.myProject.myModule内被访问。”);
}
return {
myPublicProperty: “我作为YAHOO.myProject.myModule.myPublicProperty能被访问。”
myPublicMethod: function () {
YAHOO.log(”我作为YAHOO.myProject.myModule.myPublicMethod能被访问。”);
//在myProject,我能访问私有的变量和方法
YAHOO.log(myPrivateVar);
YAHOO.log(myPrivateMethod());
//myPublicMethod的原生作用域是myProject,我们可以用“this”来访问公共成员。
YAHOO.log(this.myPublicProperty);
}
};
}();
上述代码从一个匿名函数返回包含两个成员的对象。在YAHOO.myProject.myModule内部,可通过this.myPublicProperty和this.myPublicMethod分别访问。在YAHOO.myProject.myModule外部,公共成员可通过YAHOO.myProject.myModule.myPublicProperty和YAHOO.myProject.myModule.myPublicMethod访问。
私有变量myPrivateProperty和myPrivateMethod仅能被匿名函数本身或返回对象的成员访问。尽管匿名函数立即执行并终止,但它们凭借闭包(closure)的力量得以保留——根据规则,函数的局部变量在函数返回后依然保留。只要YAHOO.myProject.myModule需要它们,这两个私有变量就不会被销毁。
YUI环境下的拖拽列表实践
实践该模式。让我们查看一个常见应用案例:假设有一个列表,其中部分项可被拖拽。应用拖拽的项上带有拖拽CSS类。
<!--这个脚本文件包含所有的YUI实用程序-->
<script type="text/javascript"
src="http://yui.yahooapis.com/2.2.2/build/utilities/utilities.js"></script>
<ul id="myList">
<li class="draggable">一项</li>
<li>二项</li> <!--二项将不能被拖拽-->
<li class="draggable">三项</li>
</ul>
<script>
YAHOO.namespace("myProject");
YAHOO.myProject.myModule = function () {
//YUI实用程序的私有简写引用:
var yue = YAHOO.util.Event,
yud = YAHOO.util.Dom;
//私有方法
var getListItems = function () {
// 注意这个地方使用其他的私有变量,包括"yud"YAHOO.util.Dom的简写:
var elList = yud.get("myList");
var aListItems = yud.getElementsByClassName(
"draggable", //得到仅有CSS类"draggable"的项
"li", //仅返回列表项
elList //限定搜索改元素的子
);
return aListItems;
};
//这个放回的对象将变成YAHOO.myProject.myModule:
return {
aDragObjects: [], //可对外访问的,存储DD对象
init: function () {
//直到DOM完全加载好,才实现列表项可拖拽:
yue.onDOMReady(this.makeLIsDraggable, this, true);
},
makeLIsDraggable: function () {
var aListItems = getListItems(); //我们可以拖拽的那些元素
for (var i=0, j=aListItems.length; i<j; i++) {
this.aDragObjects.push(new YAHOO.util.DD(aListItems[i]));
}
}
};
}();
//上面的代码已经执行,所以我们能立即访问init方法:
YAHOO.myProject.myModule.init();
</script>
这是一个简单的示例,特意写得较为详细——若按此方式操作,无疑可以写得更紧凑。当项目变得复杂且API增加时,该模式能良好扩展。通过这种方式,它避免了全局命名空间,提供了对外可访问的API方法,并支持受保护或“私有”的数据和方法。
[1]原文:《a javascript module pattern》。这是在YUI blog上的,有的地方可能打不开,可以搜一下英文的转载或者利用搜索引擎的缓存也能看。
[2]《A JavaScript Module Pattern - JavaScript的一种模组模式》这是别人的翻译,参考了不少,不过感觉挺不方便看的,这是我翻译的这篇文章的一个原因,当然最主要的原因是这篇文章算是学习YUI的最基础的文章了,整个YUI的模块模式都基于此。
JavaScript闭包与类(Class)的区别及适用场景对比
2026-11-05 15:48:57
JavaScript入门要学ES6吗?let与箭头函数等新特性解析
2026-11-05 14:49:16
JavaScript 8种数据类型详解:基本类型与引用类型的区别
2026-11-05 14:25:15
怎么在JavaScript中使用async/await优化Ajax异步流程
2026-11-05 13:56:15
JavaScript replace回调函数实现动态正则替换逻辑
2026-11-05 13:52:13
