Javascript乱弹设计模式系列.docx
- 文档编号:1012998
- 上传时间:2023-04-30
- 格式:DOCX
- 页数:16
- 大小:39.71KB
Javascript乱弹设计模式系列.docx
《Javascript乱弹设计模式系列.docx》由会员分享,可在线阅读,更多相关《Javascript乱弹设计模式系列.docx(16页珍藏版)》请在冰点文库上搜索。
Javascript乱弹设计模式系列
Javascript乱弹设计模式系列
前言
博客园谈设计模式的文章很多,我也受益匪浅,包括TerryLee、吕震宇等等的.NET设计模式系列文章,强烈推荐。
对于我,擅长于前台代码的开发,对于设计模式也有一定的了解,于是我想结合Javascript来设计前台方面的“设计模式”,以对后台“设计模式”做个补充。
开始这个系列我也诚惶诚恐,怕自己写得不好,不过我也想做个尝试,一来希望能给一些人有些帮助吧,二来从写文章中锻炼下自己,三来通过写文章对自己增加自信;如果写得不好,欢迎拍砖,我会虚心向博客园高手牛人们学习请教;如果觉得写得还可以,谢谢大家的支持了:
)
这篇主要对于单件模式的各种代码形式进行归纳总结。
可能大家没有经意,实际上,单件模式也许是我们日常前端JS开发中使用频率最高的设计模式了。
概述
在软件系统中,总有一些类只能或者必须产生一个实例对象,比如线程池,缓存,注册表等等;对于这种类,如果产生多个实例对象,就会出现各种异常状况;对于这种对象只要创建一次并且分配一次内存空间即可,所以这里也有个问题,对象所分配的内存空间的消耗,对于长期不使用的对象,这就产生资源浪费,所以利用单件模式,也可以按照需要来创建对象。
定义
单件模式确保一个类只有一个实例,并且提供一个全局访问点。
类图
分析
首先我们考虑到传统的编程语言如C#,单件模式中设置一个静态变量,可以这样表示:
public sealed class Singleton
{
static Singleton instance = null;
//
}
Singleton的构造函数设置为私有,防止Singleton多次实例化,这样就可以有以下的静态方法:
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
这样只有在第一次实例化的时候,才创建对象;通过静态方法,得到唯一实例;
这个是C#中最简单的单件模式写法。
而Javascript作为弱类型语言,有着它独特的地方,现在我就来介绍Javascript单件模式的几种形式:
1.最基本的单件模式
var LoginUser = {
name :
"匿名用户",
sex :
"保密",
setName :
function(name){
this.name = name;
},
setSex :
function(sex){
this.sex = sex;
},
getUserInfo :
function() {
return "用户名:
" + this.name + ";性别:
" +this.sex;
}
}
这里定义了一个对象(LoginUser),对象中包含了各种属性(name,sex)和方法(setName,setSex,getUserInfo);
这样我新建一个HTML页面:
//
window.onload = function() {
alert(LoginUser.getUserInfo());
LoginUser.setName("Leepy");
LoginUser.setSex("男");
//alert(LoginUser.getUserInfo());
}
function test() {
alert(LoginUser.getUserInfo());
}
可以发现,界面初始化时弹出的警告框为“用户名:
匿名用户;性别:
保密”,通过setName和setSex方法之后,点击按钮后弹出的警告框为“用户名:
Leepy;性别:
男”,说明在不同的方法作用域下,LoginUser保持着修改后的状态,因此LoginUser在页面中就保持着单一的状态。
我想大家一定也听过prototype的JS框架了吧,最新版本为实际上在它的文件中包含着很多这样类似的代码,比如从文件一开头就可以发现:
var Prototype = {
Version:
'1.6.0.3',
Browser:
{
IE:
!
!
(window.attachEvent &&
navigator.userAgent.indexOf('Opera') === -1),
Opera:
navigator.userAgent.indexOf('Opera') > -1,
WebKit:
navigator.userAgent.indexOf('AppleWebKit/') > -1,
Gecko:
navigator.userAgent.indexOf('Gecko') > -1 &&
navigator.userAgent.indexOf('KHTML') === -1,
MobileSafari:
!
!
navigator.userAgent.match(/Apple.*Mobile.*Safari/)
},
BrowserFeatures:
{
XPath:
!
!
document.evaluate,
SelectorsAPI:
!
!
document.querySelector,
ElementExtensions:
!
!
window.HTMLElement,
SpecificElementExtensions:
document.createElement('div')['__proto__'] &&
document.createElement('div')['__proto__'] !
==
document.createElement('form')['__proto__']
},
ScriptFragment:
'
可以得到下面的弹出框:
LoginUser和LoginUser.Mother的name属性已经区分开来了。
在prototype.js文件中也用到命名空间的单件模式:
var Class = {
create:
function() {
var parent = null, properties = $A(arguments);
if (Object.isFunction(properties[0]))
parent = properties.shift();
function klass() {
this.initialize.apply(this, arguments);
}
Object.extend(klass, Class.Methods);
klass.superclass = parent;
klass.subclasses = [];
if (parent) {
var subclass = function() { };
subclass.prototype = parent.prototype;
klass.prototype = new subclass;
parent.subclasses.push(klass);
}
for (var i = 0; i < properties.length; i++)
klass.addMethods(properties[i]);
if (!
klass.prototype.initialize)
klass.prototype.initialize = Prototype.emptyFunction;
klass.prototype.constructor = klass;
return klass;
}
};
Class.Methods = {
addMethods:
function(source) {
var ancestor = this.superclass && this.superclass.prototype;
var properties = Object.keys(source);
if (!
Object.keys({ toString:
true }).length)
properties.push("toString", "valueOf");
for (var i = 0, length = properties.length; i < length; i++) {
var property = properties[i], value = source[property];
if (ancestor && Object.isFunction(value) &&
value.argumentNames().first() == "$super") {
var method = value;
value = (function(m) {
return function() { return ancestor[m].apply(this, arguments) };
})(property).wrap(method);
value.valueOf = method.valueOf.bind(method);
value.toString = method.toString.bind(method);
}
this.prototype[property] = value;
}
return this;
}
};
这里实际上Class.create实现的是类的继承,具体这里我就不再阐述了,大家可以查看prototype官方的Api文档。
3.闭包方式的单件模式
如果要得到真正意义上的“私有”成员,那么闭包方式是构造单件模式的一种选择。
通过闭包的方式,只暴露一些可以公开的方法或者属性,而私有成员只在内部实现操作,而所有的属性和方法只需要实例化一次。
现在开始继续看LoginUser的例子,闭包方式单件模式(左)对比第1条基本单件模式(右)的例子:
var LoginUser = (function(){
var _name = "匿名用户";
var _sex = "保密";
return {
setName :
function(name){
_name = name;
},
setSex :
function(sex){
_sex = sex;
},
getUserInfo :
function(){
return "用户名:
" + _name + ";性别:
" + _sex;
},
getName :
function(){
return _name;
}
};
})();
var LoginUser = {
_name :
"匿名用户",
_sex :
"保密",
setName :
function(name){
this._name = name;
},
setSex :
function(sex){
this._sex = sex;
},
getUserInfo :
function() {
return "用户名:
" + this._name + ";性别:
" +this._sex;
}
}
可以发现,闭包方式将公共的方法放在return{...}中,而属性_name和_sex做为参数传入return{...}中;
现在两种方式都实现一下代码,测试一下:
window.onload = function() {
LoginUser.setName("Leepy");
LoginUser.setSex("男");
alert(LoginUser._name);
}
可以得到闭包方式单件模式(左)对比第1条基本单件模式(右)如下两个结果:
可以看出闭包方式的LoginUser无法得到_name的值,而基本方式的LoginUser可以得到_name的值;
这进一步说明了闭包方式的_name已经成为“私有”成员属性了。
而如果要得到_name的值,只有通过公开方法或者公开属性来获得,如下:
return { // 注意这里的“{”号不能够换行到下一行,不然浏览器提示错误
getName :
function() {
return _name;
}
}
这样子,alert(LoginUser.getName()); 就可以显示正确的值了。
继续看prototype.js文件中,其实也用到闭包方式的单件模式:
var Hash = Class.create(Enumerable, (function() {
function toQueryPair(key, value) {
if (Object.isUndefined(value)) return key;
return key + '=' + encodeURIComponent(String.interpret(value));
}
return {
initialize:
function(object) {
this._object = Object.isHash(object) ?
object.toObject() :
Object.clone(object);
},
_each:
function(iterator) {
for (var key in this._object) {
var value = this._object[key], pair = [key, value];
pair.key = key;
pair.value = value;
iterator(pair);
}
},
set:
function(key, value) {
return this._object[key] = value;
},
get:
function(key) {
// simulating poorly supported hasOwnProperty
if (this._object[key] !
== Object.prototype[key])
return this._object[key];
},
unset:
function(key) {
var value = this._object[key];
delete this._object[key];
return value;
},
toObject:
function() {
return Object.clone(this._object);
},
keys:
function() {
return this.pluck('key');
},
values:
function() {
return this.pluck('value');
},
index:
function(value) {
var match = this.detect(function(pair) {
return pair.value === value;
});
return match && match.key;
},
merge:
function(object) {
return this.clone().update(object);
},
update:
function(object) {
return new Hash(object).inject(this, function(result, pair) {
result.set(pair.key, pair.value);
return result;
});
},
toQueryString:
function() {
return this.inject([], function(results, pair) {
var key = encodeURIComponent(pair.key), values = pair.value;
if (values && typeof values == 'object') {
if (Object.isArray(values))
return results.concat(values.map(toQueryPair.curry(key)));
} else result
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Javascript 乱弹 设计 模式 系列