Skip to content

Commit 3e19bd9

Browse files
committed
装饰者模式
1 parent 9b1be92 commit 3e19bd9

File tree

5 files changed

+491
-0
lines changed

5 files changed

+491
-0
lines changed

fourteen-chapter/decorator.js

+234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
//装饰者模式
2+
// 给对象动态地增加职责
3+
4+
// 模拟传统面向对象语言的装饰者模式
5+
var obj = {
6+
name:'smith',
7+
address:'上海',
8+
};
9+
10+
obj.address = obj.address + '宝山区'
11+
12+
//仿飞机大战
13+
var Plane = function () {};
14+
15+
Plane.prototype.fire = function(){
16+
console.log('emit normal bullet');
17+
}
18+
19+
//增加两个装饰类,分别是导弹和原子弹
20+
var MissileDecorator = function(plane){
21+
this.plane = plane;
22+
}
23+
24+
MissileDecorator.prototype.fire = function(){
25+
this.plane.fire();
26+
console.log('emit missile')
27+
}
28+
29+
var AtomDecorator = function(plane){
30+
this.plane = plane;
31+
}
32+
33+
AtomDecorator.prototype.fire = function(){
34+
this.plane.fire();
35+
console.log('emit atom')
36+
}
37+
38+
var plane = new Plane();
39+
plane = new MissileDecorator(plane);
40+
plane = new AtomDecorator(plane);
41+
42+
plane.fire();
43+
44+
//js的装饰者模式
45+
46+
var plane = {
47+
fire:function(){
48+
console.log('emit bullet')
49+
}
50+
}
51+
52+
var missionDecorator = function(){
53+
console.log('emit missile')
54+
}
55+
56+
var atomDecorator = function(){
57+
console.log('emit atom');
58+
}
59+
60+
var fire1 = plane.fire;
61+
62+
plane.fire = function(){
63+
fire1();
64+
missileDecorator()
65+
}
66+
67+
var fire2 = plane.fire
68+
69+
plane.fire = function(){
70+
fire2();
71+
atomDecorator();
72+
}
73+
74+
plane.fire();
75+
76+
//执行顺序 fire2 => fire1 => fire => missileDecorator => atomDecorator
77+
78+
//装饰函数
79+
//为函数添加功能,最简单粗暴的方式就是直接改写该函数
80+
var a = function(){
81+
alert(1)
82+
}
83+
84+
//改写成,违反封闭开放原则
85+
var a = function(){
86+
alert(1)
87+
alert(2)
88+
}
89+
90+
//保存原引用
91+
var a = function(){
92+
alert(1)
93+
}
94+
95+
var _a = a;
96+
a = function(){
97+
_a();
98+
alert(a);
99+
}
100+
101+
a();
102+
103+
104+
//符合开放-封闭原则,增加新功能没有修改原来的代码
105+
//必须维护window.onload的变量,函数的装饰链较长,需要的中间变量变多
106+
// this 被劫持的问题
107+
window.onload = function(){
108+
alert(1)
109+
}
110+
111+
var _onload = window.onload || function(){};
112+
113+
window.onload = function(){
114+
_onload();
115+
alert(2);
116+
}
117+
118+
// this 被劫持的问题
119+
var _getElementById = document.getElementById;
120+
121+
document.getElementById = function(id){
122+
alert(1);
123+
return _getElementById(id);
124+
}
125+
126+
var button = document.getElementById('button');//报错, this 不是指向 document 指向 window
127+
128+
//改进代码,手动把document 当上下文this 传给 _getElementById;
129+
var _getElementById = document.getElementById;
130+
131+
document.getElementById = function(){
132+
alert(1);
133+
return _getElementById.apply(document,arguments);
134+
}
135+
136+
//AOP 装饰函数
137+
Function.prototype.before = function(beforeFn){
138+
var __self = this;
139+
return function(){
140+
beforeFn.apply(this,arguments);
141+
return __self.apply(this,arguments);
142+
}
143+
}
144+
145+
Function.prototype.after = function(afterFn){
146+
var __self = this;
147+
return function(){
148+
var ret = __self.apply(this,arguments);
149+
afterFn.apply(this,arguments);
150+
return ret;
151+
}
152+
}
153+
154+
//污染的原型,把原函数和新函数当作参数传递进去
155+
var before = function(fn,beforeFn){
156+
return function(){
157+
beforeFn.apply(this,arguments);
158+
return fn.apply(this,arguments);
159+
}
160+
}
161+
162+
var a = before(
163+
function(){console.log(1)},
164+
function(){console.log(2)}
165+
)
166+
167+
a = before(a,function(){console.log(3)});
168+
a();
169+
170+
//AOP 应用实例
171+
//数据上报统计
172+
//AOP 动态改变函数的参数
173+
//AOP 插件式的表单验证
174+
175+
var func = function(param){
176+
console.log(param);
177+
}
178+
func = func.before(function(param){
179+
param.b = 'b';
180+
})
181+
182+
func({a:'a'});
183+
184+
//发起ajax的伪代码
185+
var ajax = function(type,url,param){
186+
console.dir(param);
187+
}
188+
189+
ajax('get','http://xxx.com/userInfo',{name:'smit'});
190+
191+
//网站遭受了 CSRF 攻击。解决 CSRF 攻击最简单的一个办法就是在 HTTP 请求中带上一个 Token 参数
192+
var getToken = function(){
193+
return 'Token';
194+
}
195+
196+
//Token 带上太生硬了,不好移植
197+
var ajax = function(type,url,param){
198+
param = param || {};
199+
param.token = getToken();
200+
}
201+
202+
//AOP 解决
203+
var ajax = function(type,url,param){
204+
console.log(param);
205+
}
206+
207+
var getToken = function(){
208+
return 'Token';
209+
}
210+
211+
ajax = ajax.before(function(type,url,param){
212+
param.Token = getToken();
213+
})
214+
215+
ajax('get','http://xxx.com/userInfo',{name:'smith'});
216+
217+
//注意事项
218+
// 函数通过 Function.prototype.before 或者 Function.prototype.after 被装 饰之后,
219+
// 返回的实际上是一个新的函数,如果在原函数上保存了一些属性,那么这些属性会丢失
220+
221+
var func = function(){
222+
alert(1)
223+
}
224+
225+
func.a = 'a'
226+
227+
func = func.after(function(){
228+
alert(2);
229+
})
230+
231+
alert(func.a) // undefined;
232+
233+
234+

fourteen-chapter/demo.html

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<html>
2+
<title>demo1</title>
3+
<script>
4+
var plane = {
5+
fire:function(){
6+
console.log('emit bullet')
7+
}
8+
}
9+
10+
var missileDecorator = function(){
11+
console.log('emit missile')
12+
}
13+
14+
var atomDecorator = function(){
15+
console.log('emit atom');
16+
}
17+
18+
var fire1 = plane.fire;
19+
20+
plane.fire = function(){
21+
fire1();
22+
missileDecorator()
23+
}
24+
25+
var fire2 = plane.fire
26+
27+
plane.fire = function(){
28+
fire2();
29+
atomDecorator();
30+
}
31+
32+
plane.fire();
33+
</script>
34+
</html>

fourteen-chapter/demo2.html

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<html>
2+
<title>demo2</title>
3+
<body>
4+
<button id="button">button</button>
5+
</body>
6+
<script>
7+
// Function.prototype.before = function(beforeFn){
8+
// var __self = this;
9+
// return function(){
10+
// beforeFn.apply(this,arguments);
11+
// return __self.apply(this,arguments);
12+
// }
13+
// }
14+
15+
// Function.prototype.after = function(afterFn){
16+
// var __self = this;
17+
// return function(){
18+
// var ret = __self.apply(this,arguments);
19+
// afterFn.apply(this,arguments);
20+
// return ret;
21+
// }
22+
// }
23+
24+
// document.getElementById = document.getElementById.before(function () {
25+
// console.log('before ')
26+
// })
27+
28+
// var button = document.getElementById('button');
29+
// console.log('button');
30+
31+
// window.onload = function () {
32+
// console.log(1)
33+
// }
34+
35+
// window.onload = (window.onload || function () {}).after(function () {
36+
// console.log(2)
37+
// }).after(function(){
38+
// console.log(3);
39+
// })
40+
41+
42+
// var before = function(fn,beforeFn){
43+
// return function(){
44+
// beforeFn.apply(this,arguments);
45+
// return fn.apply(this,arguments);
46+
// }
47+
// }
48+
49+
// var a = before(
50+
// function(){console.log(1)},
51+
// function(){console.log(2)}
52+
// )
53+
54+
// a = before(a,function(){console.log(3)});
55+
// a();
56+
57+
</script>
58+
</html>

fourteen-chapter/demo3.html

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<html>
2+
<title>demo3</title>
3+
<body>
4+
<button id="button" tag='login'>点击打开登录浮层</button>
5+
</body>
6+
<script>
7+
8+
// var showLogin = function () {
9+
// console.log('打开登录浮层');
10+
// log(this.getAttribute('tag'));
11+
// }
12+
13+
// var log = function(tag){
14+
// console.log('上报标签为: ' + tag);
15+
// (new Image).src = 'http://xxx.com/report?tag='+tag;
16+
// }
17+
18+
// document.getElementById('button').onclick = showLogin;
19+
20+
//showLogin 耦合了 打开登录浮层和数据上报的功能
21+
Function.prototype.after = function(afterFn){
22+
var __self = this;
23+
return function(){
24+
var ret = __self.apply(this,arguments);
25+
afterFn.apply(this,arguments);
26+
return ret;
27+
}
28+
}
29+
30+
31+
var showLogin = function(){
32+
console.log('打开登录浮层');
33+
}
34+
35+
var log = function(){
36+
console.log('上报的标齐为: '+ this.getAttribute('tag'));
37+
}
38+
39+
showLogin = showLogin.after(log);
40+
41+
document.getElementById('button').onclick = showLogin;
42+
43+
</script>
44+
</html>

0 commit comments

Comments
 (0)