Javascript乱弹设计模式系列Word文件下载.docx
- 文档编号:1221591
- 上传时间:2023-04-30
- 格式:DOCX
- 页数:16
- 大小:39.71KB
Javascript乱弹设计模式系列Word文件下载.docx
《Javascript乱弹设计模式系列Word文件下载.docx》由会员分享,可在线阅读,更多相关《Javascript乱弹设计模式系列Word文件下载.docx(16页珍藏版)》请在冰点文库上搜索。
null)
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()
用户名:
+
;
性别:
+this.sex;
这里定义了一个对象(LoginUser),对象中包含了各种属性(name,sex)和方法(setName,setSex,getUserInfo);
这样我新建一个HTML页面:
<
script
type="
text/javascript"
>
window.onload
alert(LoginUser.getUserInfo());
LoginUser.setName("
Leepy"
);
LoginUser.setSex("
男"
//alert(LoginUser.getUserInfo());
function
test()
/script>
input
button"
value="
test"
onclick="
test();
/>
可以发现,界面初始化时弹出的警告框为“用户名:
匿名用户;
保密”,通过setName和setSex方法之后,点击按钮后弹出的警告框为“用户名:
Leepy;
男”,说明在不同的方法作用域下,LoginUser保持着修改后的状态,因此LoginUser在页面中就保持着单一的状态。
我想大家一定也听过prototype的JS框架了吧,最新版本为实际上在它的文件中包含着很多这样类似的代码,比如从文件一开头就可以发现:
Prototype
Version:
'
1.6.0.3'
Browser:
IE:
!
(window.attachEvent
&
navigator.userAgent.indexOf('
Opera'
)
===
-1),
Opera:
-1,
WebKit:
AppleWebKit/'
Gecko:
Gecko'
-1
KHTML'
MobileSafari:
navigator.userAgent.match(/Apple.*Mobile.*Safari/)
},
BrowserFeatures:
XPath:
document.evaluate,
SelectorsAPI:
document.querySelector,
ElementExtensions:
window.HTMLElement,
SpecificElementExtensions:
document.createElement('
div'
)['
__proto__'
]
==
form'
]
ScriptFragment:
script[^>
]*>
([\\S\\s]*?
)<
\/script>
JSONFilter:
/^\/\*-secure-([\s\S]*)\*\/\s*$/,
emptyFunction:
{
K:
function(x)
x
};
//以下是它的使用
(Prototype.Browser.MobileSafari)
Prototype.BrowserFeatures.SpecificElementExtensions
false;
可以看出,Version、Browser、BrowserFeatures、ScriptFragment、JSONFilter作为Prototype对象的属性,而emptyFUnction、K作为Prototype对象的方法;
因此它就是一个最基本的单件模式。
由于Javascript的语言特性,可以在后期动态添加,删除,修改属性:
如:
LoginUser.age=24;
那么LoginUser对象便增加了age属性;
而如:
deleteLoginUser.name;
那么LoginUser对象就删除了name属性;
LoginUser.name="
cnblogs"
;
那么LoginUser对象的“私有”属性不需要通过setName的“公有”方法仍然能够做出修改。
因为根据设计模式原则:
对扩展开放而对修改关闭,显然违背了该条准则。
为了防止这种情况的发生,到时候会引入闭包的方式,稍后会说明。
2.命名空间的单件模式
命名空间可以很好地划分属性和方法的归属,以及可以防止属性和方法被轻易的修改,通过访问各自的命名空间得到对应我们想要的属性和方法。
这里还是以上面的LoginUser为例:
LoginUser.Mother
母亲姓名"
career
职位"
setCareer
function(career){
this.career
career;
LoginUser.name
的母亲名字:
职业:
+this.career;
从代码中看出,这里我把LoginUser作为“命名空间”,而LoginUser.Mother作为它的一个“全局变量”,这样做的好处可以防止LoginUser的属性和方法被轻易地覆盖,通过LoginUser.×
×
,以致于LoginUser.×
.×
(如LoginUser.Mother.Brother)来划分属性和方法的归属,如LoginUser中的name属性和LoginUser.Mother中的name属性是区分开来的。
LoginUser.Mother.setName("
admin"
LoginUser.Mother.setCareer("
农民"
alert(LoginUser.Mother.getUserInfo());
可以得到下面的弹出框:
LoginUser和LoginUser.Mother的name属性已经区分开来了。
在prototype.js文件中也用到命名空间的单件模式:
Class
create:
parent
null,
properties
$A(arguments);
(Object.isFunction(properties[0]))
properties.shift();
klass()
this.initialize.apply(this,
arguments);
Object.extend(klass,
Class.Methods);
klass.superclass
parent;
klass.subclasses
[];
(parent)
subclass
subclass.prototype
parent.prototype;
klass.prototype
subclass;
parent.subclasses.push(klass);
for
(var
i
0;
properties.length;
i++)
klass.addMethods(properties[i]);
(!
klass.prototype.initialize)
klass.prototype.initialize
Prototype.emptyFunction;
klass.prototype.constructor
klass;
Class.Methods
addMethods:
function(source)
ancestor
this.superclass
this.superclass.prototype;
Object.keys(source);
Object.keys({
toString:
true
}).length)
properties.push("
toString"
valueOf"
0,
length
length;
i++)
property
properties[i],
value
source[property];
(ancestor
Object.isFunction(value)
value.argumentNames().first()
$super"
method
value;
(function(m)
ancestor[m].apply(this,
arguments)
})(property).wrap(method);
value.valueOf
method.valueOf.bind(method);
value.toString
method.toString.bind(method);
this.prototype[property]
this;
这里实际上Class.create实现的是类的继承,具体这里我就不再阐述了,大家可以查看prototype官方的Api文档。
3.闭包方式的单件模式
如果要得到真正意义上的“私有”成员,那么闭包方式是构造单件模式的一种选择。
通过闭包的方式,只暴露一些可以公开的方法或者属性,而私有成员只在内部实现操作,而所有的属性和方法只需要实例化一次。
现在开始继续看LoginUser的例子,闭包方式单件模式(左)对比第1条基本单件模式(右)的例子:
(function(){
_name
_sex
function(){
_sex;
getName
_name;
})();
this._name
this._sex
+this._sex;
可以发现,闭包方式将公共的方法放在return{...}中,而属性_name和_sex做为参数传入return{...}中;
现在两种方式都实现一下代码,测试一下:
alert(LoginUser._name);
可以得到闭包方式单件模式(左)对比第1条基本单件模式(右)如下两个结果:
可以看出闭包方式的LoginUser无法得到_name的值,而基本方式的LoginUser可以得到_name的值;
这进一步说明了闭包方式的_name已经成为“私有”成员属性了。
而如果要得到_name的值,只有通过公开方法或者公开属性来获得,如下:
//
注意这里的“{”号不能够换行到下一行,不然浏览器提示错误
这样子,alert(LoginUser.getName());
就可以显示正确的值了。
继续看prototype.js文件中,其实也用到闭包方式的单件模式:
Hash
Class.create(Enumerable,
(function()
toQueryPair(key,
value)
(Object.isUndefined(value))
key;
key
='
encodeURIComponent(String.interpret(value));
initialize:
function(object)
this._object
Object.isHash(object)
?
object.toObject()
Object.clone(object);
_each:
function(iterator)
in
this._object)
this._object[key],
pair
[key,
value];
pair.key
pair.value
iterator(pair);
set:
function(key,
this._object[key]
get:
function(key)
simulating
poorly
supported
hasOwnProperty
(this._object[key]
Object.prototype[key])
this._object[key];
unset:
delete
toObject:
Object.clone(this._object);
keys:
this.pluck('
key'
values:
value'
index:
function(value)
match
this.detect(function(pair)
});
match.key;
merge:
this.clone().update(object);
update:
Hash(object).inject(this,
function(result,
pair)
result.set(pair.key,
pair.value);
result;
toQueryString:
this.inject([],
function(results,
encodeURIComponent(pair.key),
values
pair.value;
(values
typeof
object'
(Object.isArray(values))
results.concat(values.map(toQueryPair.curry(key)));
}
else
result
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Javascript 乱弹 设计 模式 系列