JavaScript 常用设计模式详解:单例、工厂、适配与外观
本文详细介绍 JavaScript 中四种常见的设计模式:单例模式通过闭包实现资源懒加载;工厂模式利用构造函数动态创建对象;适配器模式解决接口兼容性问题;外观模式封装复杂子系统以简化调用。结合具体代码示例,帮助开发者理解并应用这些模式优化前端架构。
JavaScript 作为一种面向对象语言,虽然出现时间较晚,但目前已是最流行的脚本语言之一。随着微信商城等页面的兴起,JavaScript 在前端开发中的地位愈发重要,程序员和互联网从业者都应关注其发展趋势。
若希望在前端领域深入发展,掌握设计模式是必经之路。本文将介绍几种常见的设计模式及其应用场景。
单例模式
一、单例模式
单例模式(也称单子模式或单体模式)是软件设计中简单且常用的一种模式。在 JavaScript 中,实现单例的方式多样,最简单的方式是使用对象字面量,其中可包含大量属性和方法:
var mySingleton = {
property1: "something",
property2: "something else",
method1: function () {
console.log('hello world');
}};
若需扩展该对象,可添加私有成员和方法,并通过闭包封装这些变量和函数声明。仅暴露所需的公共成员和方法,示例代码如下:
var mySingleton = function () {
/* 这里声明私有变量和方法 */
var privateVariable = 'something private';
function showPrivate() {
console.log(privateVariable);
}
/* 公有变量和方法(可以访问私有变量和方法) */
return {
publicMethod: function () {
showPrivate();
},
publicVar: 'the public can see this!'
};
};
var single = mySingleton();
single.publicMethod(); // 输出 'something private'
console.log(single.publicVar); // 输出 'the public can see this!'
上述代码已具备良好结构,但若希望实现延迟初始化以节约资源,可在另一个构造函数中初始化代码,如下所示:
var Singleton = (function () {
var instantiated;
function init() {
/*这里定义单例代码*/
return {
publicMethod: function () {
console.log('hello world');
},
publicProperty: 'test'
};
}
return {
getInstance: function () {
if (!instantiated) {
instantiated = init();
}
return instantiated;
}
};
})();
/*调用公有的方法来获取实例:*/
Singleton.getInstance().publicMethod();
工厂模式
二、工厂模式
工厂模式通过一个方法决定创建哪个类的实例,这些实例通常拥有相同的接口。该模式适用于实例类型在编译期无法确定、而在执行期决定的场景。通俗而言,如同公司茶水间的饮料机,选择咖啡或牛奶取决于按下的按钮。
实例:
function A( name ){
this.name = name;
}
function ObjectFactory(){
var obj = {},
Constructor = Array.prototype.shift.call( arguments );
obj.__proto__ = typeof Constructor .prototype === 'number' ? Object.prototype
: Constructor .prototype;
var ret = Constructor.apply( obj, arguments );
return typeof ret === 'object' ? ret : obj;
}
var a = ObjectFactory( A, 'svenzeng' );
alert ( a.name ); //svenzeng
这段代码源自 ES5 中 new 和构造器的相关说明。可以看出,new 操作本质上是对象的复制和改写过程,具体生成什么由调用 ObjectFactory 时传入的参数决定。
适配模式
三、适配模式
适配模式主要解决接口不兼容问题。借助适配器,可在不修改原有不兼容接口的情况下,为使用者提供统一的包装接口。虽然表面与门面模式相似,均是对其他对象或接口进行包装,但适配器模式侧重于解决兼容性问题,而门面模式侧重于方便性。
例如,一个简单的学生查询学科成绩的方法:
function selectScore( name, id, course_id ){
// arguments 姓名 学号 课程id
...
}
若需获取班级某门学科的整体成绩列表,而手头仅有每个学生的如下数据:
[
{ name: 'lily', studentID: '0911' },
{ name: 'suny', studentID: '0912' },
...
]
假设需查询英语课程(ID 为 101)的成绩,使用适配器方式处理参数兼容性是恰当的选择。
function selectEnglishScore( stutentObj ){
selectScore( stutentObj.name, stutentObj.studentID , 101);
}
这是最简单的适配器处理参数兼容的形式。简言之,适配器模式的核心在于适配,即解决兼容问题。
示例二:若需将 jQuery 中的 $ 选择器改为 $id 以适配项目,可通过编写方法将 $ 转换为 $id,如下所示:
$id = function( id ){
return jQuery( '#' + id )[0];
}
外观模式
四、外观模式
外观模式(又称门面模式)是一种简单且无处不在的模式。它提供一个高层接口,使客户端或子系统调用更加便捷。用一段简单的代码表示:
var getName = function(){
return ''svenzeng"
}
var getSex = function(){
return 'man'
}
若需分别调用 getName 和 getSex 函数,可使用更高层的接口 getUserInfo 进行调用:
var getUserInfo = function(){
var info = a() + b();
return info;
}
或许有人会问,为何不一开始就将 getName 和 getSex 的代码合并,例如:
var getNameAndSex = function(){
return 'svenzeng" + "man";
}
答案显而易见:正如食堂炒菜师傅不会因预定烧鸭和白菜就将两者炒在一锅中,而是提供烧鸭饭套餐。在程序设计中,需保证函数或对象处于合理粒度,因为并非所有用户都同时需要相同功能。外观模式的优势在于隐藏实现细节,用户只需关注高层接口。例如在烧鸭饭套餐故事中,用户不关心师傅先做烧鸭还是炒白菜,也不关心鸭子来源。
最后,提供一个常见的外观模式示例:
var stopEvent = function( e ){ //同时阻止事件默认行为和冒泡
e.stopPropagation();
e.preventDefault();
}
本文介绍的设计模式暂告一段落。若需了解更多设计模式,可参考汤姆大叔的博客。此外,许多设计模式实质是将解决问题的方法细化,如查看 prototype 或 jQuery 源码,会发现其中大量应用了设计模式。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持本站!
JS处理含Emoji或中文的字符串转数组乱码问题
2026-11-05 16:12:28
JS怎么使用展开运算符合并对象
2026-11-05 14:42:18
ES6+环境下判断JS对象为空的简洁写法
2026-11-05 12:12:23
怎么通过replacer函数自定义JS中JSON的格式化输出
2026-11-05 11:19:44
JS正则表达式基础:字面量与RegExp构造函数的区别及常用元字符
2026-11-05 11:16:58
