形式1 – 单例形式
单例形式的中心是确保只需一个实例,而且供应全局接见。
特性:
满足“单一职责准绳” : 运用代办形式,不在组织函数中推断是不是已竖立过该单例;
满足惰性准绳
运用:
弹出上岸窗口。
实例:
var getSingle = function (fn) {
var res;
return function() {
return res || (res = fn.apply(this, arguments));
}
}
var createPopup() {
var div = document.createElement('div');
div.innerHTML = "Login window";
div.style.display = "none";
document.body.appendChild(div);
return div;
}
var createLoginPopup = getSingle(createPopup); //create popup div here by using a given function, 满足两个准绳
document.getElementById("loginBt").onclick = function() {
var popup = createLoginPopup();
pop.style.display = "block";
}
形式2 – 战略形式
定义一个个能够互相替代的算法,而且把他们封装起来。
特性:
相符开放-关闭准绳 : 要修正运用的算法时没必要深切函数内部举行修正,只需修正战略类;
将算法的完成与运用分脱离,进步算法复用性;
经由历程组合、托付和多态防止多重前提挑选语句;
运用:
动画完成差别的缓动效果。
平常分为两个部份:战略类于环境类。战略类用于封装种种算法,而且担任详细的盘算历程; 环境类担任吸收用户的要求,而且把要求托付给某一个战略类。由于各个战略类完成的算法和盘算的效果差别,而环境类挪用战略类的要领倒是雷同的,这就表现了多态性。要想完成差别的算法,只须要替代环境类中的战略类即可。
在js中,我们没必要组织战略类,可直接运用函数作为战略对象。
示例:
var strategies = {
"s1": function() {
//algo 1
},
"s2": function() {
//algo 2
},
"s3": function() {
//algo 3
}
}
var someContext = new SomeConext();
someContext.start("s1"); //using s1 to calculate
//someContext.add("s1"); or add s1 as a rule for validation
形式3 – 代办形式
代办就像一个经纪人,当用户不方便直接接见某个对象或许须要对接见举行一些过滤/加工时,能够经由历程代办来举行对象接见。代办会对要求举行一些处置惩罚,然后再将要求传递给本体。
平常分为庇护代办和假造代办:
庇护代办担任过滤掉一些要求;
假造代办则是将一些花消比较大的操纵延晚到真正他的时刻再去竖立,比方new一个对象。
特性:
保证对象相符单一职责准绳;
运用:
图片预加载, 兼并http要求, 惰性加载, 缓存代办(防止反复盘算,能够写一个通用的缓存对象(实在就是一个闭包),将高阶函数作为参数传入)。
形式4 – 迭代器形式
望文生义,迭代器能够将关于一个聚合对象内部元素的接见与营业逻辑分脱离。
平常分为内部迭代器和外部迭代器:
内部迭代器只需一次初始挪用,不须要体贴迭代器的内部完成;
外部迭代器须要显式地要求下一个元素,因而能够手工掌握迭代历程和递次,比方挪用iterator.next();
无论是哪一种迭代器,只需聚合对象有length属性而且能够经由历程下标接见,那末就能够被迭代。因而类数组对象及字面量对象(用for in)都能够。
绝大部份言语都内置了迭代器。
运用:
能够经由历程增添停止前提来中缀迭代:在callback函数中推断,假如return值为false,则经由历程break跳出迭代轮回。
由此能够设想依据浏览器范例竖立的返回对象,按优先级一个个迭代。
形式5 - 定阅宣布形式
将很多对象弱耦合起来,当一个对象的状况发生变化时,一切定阅了该变化的对象都邑收到关照。
DOM事宜是典范的定阅宣布形式,同时我们还能够自定义事宜:
var event = {
clients : {},
listen : function (signal,fn){
if(!this.clients[signal]) {
this.clients[signal] = [];
}
this.clients[signal].push(fn);
},
trigger: function (arguments){ //not only trigger the event, but also send some data
var sig = Array.prototype.shift.call(arguments);
fns = this.clients[sig];
if(!fns || fns.length === 0) return false;
for(var i = 0; i < fns.length; i++) {
var fn = fns[i];
fn.apply(this, arguments);
}
},
remove: function (signal,fn){
var fns = this.clients[signal];
if(!fns) return false;
if(!fn) {
//remove all fns
delete this.clients[signal];
} else {
for(var i = 0; i <fns.length; i++) {
var _fn = fns[i];
if(_fn === fn) {
fns.splice(i,1);
}
}
}
}
}
event.listen('click',function(data){
console.log(data);
});
event.trigger('click', "Someone clicked!");
能够经由历程离线音讯栈来保留没有被定阅的然则发生了的事宜,比及有人定阅再顺次掏出实行。
运用:
网站登录-当用户登录胜利而且ajax返回数据后,trigger事宜,须要用到用户数据的衬着模块定阅该事宜。
形式6-敕令形式
能够处理要求发送者和要求接受者之间的耦合关联。实际上,我们只须要挪用command对象中的execute要领就行,他会自动挪用敕令吸收者对应的敕令。
示例:
var tv = {
open: function() {
console.log("open tv");
},
close: function() {
console.log("turn off tv");
},
nextChannel: function() {
console.log("next channel");
}
}
//相称于我把receiver的一些可用操纵封装到command对象里了,而且供应了一致的接口
var openTVCmd = function(receiver) {
return {
execute: function(){
receiver.open();
},
undo : function() {
//go to previous channel
}
}
}
var btn1 = document.getElementById("btn1");
var btn2 = document.getElementById("btn2");
var setCmd = function(button, cmd) {
button.onclick = function(){
cmd.execute();
}
}
var opentvcmd = new openTVCmd();
setCmd(btn1, opentvcmd);
btn2.onclick = function(){ //undo command
opentvcmd.undo();
}
运用:
可完成敕令的打消和重做,只需记载一个oldState或许运用一个缓存来寄存汗青敕令;
可完成敕令行列,将command对象压入客栈,只需顺次挪用他们的execute函数,由此可完成宏敕令;
可分为智能敕令和傻瓜敕令:
1.智能敕令不须要知道receiver,可本身完成要求,代码上相似战略形式,但目标差别;
2.傻瓜敕令则只担任将要求传递给真正的receiver。
形式7-组合形式
组合形式将对象组合成树形构造,以示意层级构造。借助于对象的多态性,它使得用户能够一致地看待组合对象(单个对象的组合)和单个对象。
运用:
可完成宏敕令,只须要挪用根结点的execute,顺序会自动遍历整棵树并顺次实行各中心节点和恭弘=叶 恭弘结点的execute函数。重点是,恭弘=叶 恭弘结点与中心结点有一致托言。
可用来模仿文件和文件夹层级构造:
示例:
var Folder = function(name) {
this.name = name;
this.files = [];
}
Folder.prototype.add = function(file) {
this.files.push(file);
}
Folder.prototype.scan = function() {
console.log("begin scanning folder "+ this.name);
for(var i=0; i<this.files.length; i++) {
this.files[i].scan();
}
}
var File = function(name) {
this.name = name;
}
File.prototype.add = function() {
throw new Error("cannot add files to a file!");
}
File.prototype.scan = function() {
console.log("begin scanning "+this.name);
}
var folder1 = new Folder("fo1");
var folder2 = new Folder("fo2");
var file1 = new File("fi1");
var file2 = new File("fi2");
folder1.add(file1);
folder2.add(file2);
folder2.add(folder1);
注重,层级1与层级2结点之间并不是父子关联,只是由于他们有一致的托言而被联络在一起。
能够对这两种结点竖立双向映照,纵然文件1内里含有其父结点的援用,这模样在删除一个文件时就须要将其在其父结点的files中删除。
组合形式使得用户能够疏忽组合对象和单个对象的差别而一致看待,但这也会使得每一个对象看上去都差不多,增添代码明白的难度。
P.s. 本文总结自《JavaScript设想形式与开辟实践》,曾探著