克隆的原型模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var Plane = function(){
this.blood = 100;
this.attackLevel = 1;
this.defensLevel = 1;
}

var plane = new Plane();

plane.blood = 500;
plane.attackLevel = 10;
plane.defensLevel = 8;

var clonePlane = Object.create(plane);

clonePlane.blood = 1000;

console.log(plane + " ... " + clonePlane);
1
2
3
4
5
6
7
8
9
10
11
//输出结果
Plane {blood: 500, attackLevel: 10, defensLevel: 8}
attackLevel: 10
blood: 500
defensLevel: 8
__proto__: Object


Plane {blood: 1000}
blood: 1000
__proto__: Plane

拷贝扩展

如果只是拷贝自身可枚举属性,就可以只用 Object.assign 方法;
如果是要拷贝原型上的属性,就需要 Object.assign , Object.create, Object.getPrototypeOf 方法结合使用
如果是拷贝get/set 属性,就需要结合 Ojbect.getOwnPropertyDescriptors 方法

基于原型链的委托机制就是原型继承的本质

javascript 根对象 Object.prototype

惰性加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var addEvent = function(elem,type,handler){
if(window.addEventListener){
addEvent = function(elem,type,handler){
elem.addEventListener(type,handler,false);
}
}else if(window.attendEvent){
addEvent = function(elem,type,handler){
elem.attendEvent('on' + type,handler);
}
}
addEvent(elem,type,handler);
}

var div= document.getElementById('test');
addEvent(div, 'click', function(){
div.getElementsByTagName("span")[0].innerHTML = "1";
})
addEvent(div, 'click', function(){
div.getElementsByTagName("span")[0].innerHTML += "2";
})
测试惰性加载

透明的单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var CreateDiv = (function(){
var instance;
var CreateDiv= function(html){
if(instance){
return instance;
}
this.html = html;
this.init();
return instance = this;
}

CreateDiv.prototype.init = function(){
var div = document.createElement('div');
div.innerHTML = this.html;
document.getElementById('test2').appendChild(div);
}

return CreateDiv;
})();

var a = new CreateDiv('svenOne');
var b = new CreateDiv('svenTwo');

透明的单例模式

代理实现单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var CreateDiv= function(html){
this.html = html;
this.init();
}

CreateDiv.prototype.init = function(){
var div = document.createElement('div');
div.innerHTML = this.html;
document.body.appendChild(div);
}

var ProxySingletonCreateDiv = (function(){
var instance;
return function(html){
if(!instance){
instance = new CreateDiv(html);
}
return instance;
}
})();

var a = new ProxySingletonCreateDiv('svenOne');
var b = new ProxySingletonCreateDiv('svenTwo');

单例模式的核心是确保只有一个实例,并提供全局访问

1、使用命名空间
2、使用闭包封装私有变量

通用惰性单例

1
2
3
4
5
6
var getSingle = function(fn){
var result;
return function(){
return result || (result = fn.apply(this, arguments));
}
}

策略模式

核心思想:定义一系列算法,规则,把它们封装起来,并使它们可以互相替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var strategies = {
"s": function(salary){
return salary*4;
},
"a": function(salary){
return salary*3;
},
"b": function(salary){
return salary*2;
}
}

var calcBonus = function(level, salary){
return strategies[level](salary);
}

代理模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var myImage = (function(){
var imgNode = document.createElement('img');
document.getElementById('test3').appendChild(imgNode);

return {
setSrc: function(src){
imgNode.src = src;
}
}
})();

var proxyImage = (function(){
var img = new Image;
img.onload = function(){
myImage.setSrc(this.src);
}
return {
setSrc: function(src){
myImage.setSrc('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1565173670729&di=07d74096a6b6f920de7dda6357ac6e00&imgtype=0&src=http%3A%2F%2Fww1.sinaimg.cn%2Flarge%2F005Yxgwijw1fa0o6vvr5eg30m80go0st.gif');
img.src = src;
}
}
})();

proxyImage.setSrc("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1565173348965&di=e55e9ac7b8eaf92a2d53eb45175f8ed9&imgtype=0&src=http%3A%2F%2Fimg.mp.itc.cn%2Fupload%2F20170722%2Fbe087a0f5b434ffdb57df04115cfc0d1_th.jpg");

代理模式

迭代器模型

1
2
3
4
5
6
7
8
9
10
11
var each = function(ary, callback){
for(var i =0, l = ary.length; i<l; i++){
callback.call(ary[i], i, ary[i]);
}
}

each([1,2,3], function(i,n){
var p = document.createElement('p');
p.innerHTML = "i: " + i + " n: " + n;
document.getElementById('test4').appendChild(p);
});
内部迭代器模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//外部迭代器
var Iterator = function(obj){
var current = 0,
next = function(){
current += 1
},
isDone = function(){
return current >= obj.length;
},
getCurrItem = function(){
return obj[current];
};

return{
next: next,
isDone: isDone,
getCurrItem: getCurrItem,
length: obj.length,
}
}

var compare = function(a,b){
if(a.length !== b.length){
console.log("a 和 b 不相等!");
}
while(!a.isDone() && !b.isDone()){
if(a.getCurrItem() !== b.getCurrItem()){
throw new Error("a 和 b 不相等!")
}
a.next();
b.next();
}
console.log("a 和 b 相等!");
}
````

#### 发布-订阅模式

```js
var event = {
clientList: {},
listen: function(key, fn){
if(!this.clientList[key]){
this.clientList[key] = [];
}
this.clientList[key].push(fn);
},
trigger: function(){
var key = [].shift.call(arguments),
fns = this.clientList[key];
if(!fns || fns.length ===0){
return false;
}
for(var i = 0, fn; fn=fns[i++]){
fn.apply(this, arguments);
}
}
}

var installEvent = function(obj){
for(var i in event){
obj[i] = event[i];
}
}

命令模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var MenuBar = {
refresh: function(){
console.log("刷新操作!");
}
}

var RefreshMenuBarCommand = function(receiver){
return {
execute: function(){
receiver.refresh();
}
}
}

var SetCommand = funciton(btn, command){
btn.onclick = funciton(){
command.execute();
}
}

var r = RefreshMenuBarCommand(MenuBar);
SetCommand(btn, r);

宏命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
var a = {
exec: function(){
console.log("执行 a 命令!");
}
}

var b = {
exec: function(){
console.log("执行 b 命令!");
}
}

var c = {
exec: function(){
console.log("执行 c 命令!");
}
}

var MacroCommand = function(){
return {
commLists:[],
add: function(command){
this.commLists.push(command);
},
execute: function(){
for(var i=0, command; command= this.commLists[i++]){
command.exec();
}
}
}
}

var m = MacroCommand();
m.add(a);
m.add(b);
m.add(c);

m.execute();

模板方式模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var Beverage = function(){};

Beverage.prototype.boilWater = function(){
console.log("把水煮沸!")
};
Beverage.prototype.brew = function(){};
Beverage.prototype.pourInCup = function(){};
Beverage.prototype.addCondiments = function(){};

//钩子方法
Beverage.prototype.customerWantsCondiments = function(){
return true;
};

Beverage.prototype.init = function(){
this.boilWater();
this.brew();
this.pourInCup();
if(this.customerWantsCondiments){
this.addCondiments();
}
};

var Coffee = function(){};
Coffee.prototype = new Beverage();
Coffee.prototype.brew = function(){

}
Coffee.prototype.pourInCup = function(){

}
Coffee.prototype.addCondiments = function(){

}
Coffee.prototype.customerWantsCondiments = function(){
return window.confirm("请问需要调料吗?");
};

var coffee = new Coffee();
coffee.init();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

var Beverage = function(param){
var boilWater = function(){
console.log("把水煮沸!")
}
var brew = param.brew || function(){ throw new Error("必须传递方法!")}
var pourInCup = param.pourInCup || function(){ throw new Error("必须传递方法!")}
var addCondiments = param.addCondiments || function(){ throw new Error("必须传递方法!")}

var F= function(){};
F.prototype.init = function(){
boilWater();
brew();
pourInCup();
addCondiments();
}

return F;
}

var Coffee = Beverage({
brew:function(){},
pourInCup:function(){},
addCondiments:function(){},
})

享元模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var Model = function(sex){
this.sex = sex;
}
Model.prototype.takePhoto = function(){
console.log('sex: ' + this.sex + ' underwear: ' + this.underwear);
}

var male = new Model('male'),
female = new Model('female');

for(var i=0; i<=50; i++){
male.underwear = 'underwear' + i;
female.underwear = 'underwear' + i;

male.takePhoto();
female.takePhoto();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//对象池
var objFactory = function(createOjFn){
var objPool =[];
return {
create: function(){
var obj = objPool.length === 0?
createOjFn.apply(this,arguments):objPool.shift();
return obj;
},
recover: function(obj){
objPool.push(obj);
}
}
}

var iframeFactory = objFactory(function(){
var iframe = document.createElement('iframe');
document.getElementById('test5').appendChild(iframe);

iframe.onload = function(){
iframe.onload = null;
iframeFactory.recover(iframe);
}

return iframe;
});

var iframe1 = iframeFactory.create();
iframe1.src = 'https://www.baidu.com';

对象池

职责链模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
var order1 = function(type,pay,stock){
if(type===1 && pay){
console.log("执行 1...")
}else{
return 'nextSuccessor';
}
}

var order2 = function(type,pay,stock){
if(type===2 && pay){
console.log("执行 2...")
}else{
return 'nextSuccessor';
}
}

var orderNormal = function(type,pay,stock){
if(stock>0){
console.log("执行默认...")
}else{
console.log("未执行...")
}
}

var Chain = function(fn){
this.fn = fn;
this.successor = null;
}

Chain.prototype.setNextSuccessor = function(successor){
return this.successor = successor;
}

Chain.prototype.passRequest = function(){
var ret = this.fn.apply(this,arguments);

if(ret === 'nextSuccessor'){
return this.successor && this.successor.passRequest.apply(this.successor, arguments);
}

return ret;
}

Chain.prototype.next = function(){
return this.successor && this.successor.passRequest.apply(this.successor, arguments);
}

var chain1 = new Chain(order1);
var chain2 = new Chain(order2);
var chainNormal = new Chain(orderNormal);

chain1.setNextSuccessor(chain2);
chain2.setNextSuccessor(chainNormal);

chain1.passRequest(1,true, 500);
chain1.passRequest(2,true, 500);

//异步责任链
var fn1 = new Chain(function(){
console.log('1');
return 'nextSuccessor';
})
var fn2 = new Chain(function(){
console.log('2');
var self = this;
setTimeout =(function(){
self.next();
},1000);
})
var fn3 = new Chain(function(){
console.log('3');
})

fn1.setNextSuccessor(fn2).setNextSuccessor(fn3);
fn1.passRequest();

//AOP 责任链
Function.prototype.afterFn = function(fn){
var self = this;
return function(){
var ret = self.apply(this, arguments);
if(ret){
return fn.apply(this, arguments);
}

return ret;
}
}