# 发布/订阅模式
我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern)
- 发布/订阅模式
- 订阅者
- 发布者
- 信号中心
// 事件触发器
class EventEmitter {
constructor() {
// { 'click': [fn1, fn2], 'change': [fn] }
this.subs = Object.create(null); // 不设置原型属性 提升性能
}
// 注册事件
$on(eventType, handler) {
this.subs[eventType] = this.subs[eventType] || [];
this.subs[eventType].push(handler);
}
// 触发事件
$emit(eventType) {
if (this.subs[eventType]) {
this.subs[eventType].forEach((handler) => {
handler();
});
}
}
}
// 测试
let em = new EventEmitter();
em.$on("click", () => {
console.log("click1");
});
em.$on("click", () => {
console.log("click2");
});
em.$emit("click");
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
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
# 观察者模式
- 观察者(订阅者)- Watcher update():当事件发生时,具体要做的事情
- 目标(发布者)- Dep
- subs 数组:存储所有的观察者
- addSub():添加观察者
- notify():当事件发生,调用所有观察者的 updata() 方法
- 没有事件中心
// 发布者-目标
class Dep {
constructor() {
// 记录所有的订阅者
this.subs = [];
}
// 添加订阅者
addSub(sub) {
if (sub && sub.update) {
this.subs.push(sub);
}
}
// 发布通知
notify() {
this.subs.forEach((sub) => {
sub.update();
});
}
}
// 订阅者-观察者
class Watcher {
update() {
console.log("update");
}
}
// 测试
let dep = new Dep();
let watcher = new Watcher();
dep.addSub(watcher);
dep.notify();
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
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
# 发布订阅/观察者模式 总结
观察者模式是由具体目标调度,比如当事件触发,Dep 就会去调用观察者的方法,所以观察者模式的订阅者与发布者之间是存在依赖的。
发布/订阅模式由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在。

# 工厂模式
- 目的: 方便我们大量创建对象
- 场景: 当某个对象经常被创建的时候
//弹窗
function infoPop(){
}
function confirmPop(){
}
function cancelPop(){
}
function pop(type,content,color){
if(this instanceof pop){
var s=new this[type](content,color);
return s;
}else{
return new pop(type,content,color);
}
/*if(this instanceof pop){
return pop(type,content,color)
}else{
}
function infoPop(){
}
function confirmPop(){
}
function cancelPop(){
}
switch(type) {
case 'infoPop':
return new infoPop(content,color);
case 'confirmPop':
return new confirmPop(content,color);
case 'cancelPop':
return new cancelPop(content,color);
}*/
}
pop.prototype.infoPop=function(){
console.log('infoPop');
}
pop.prototype.confirmPop=function(){
}
pop.prototype.cancelPop=function(){
}
//pop('infoPop','hello','red');
var data=[
{
type:'infoPop',
content:'hello',
color:'red'
},
{
type:'infoPop',
content:'good good study',
color:'red'
},
{
type:'confirmPop',
content:'good good study',
color:'green'
},
];
data.forEach((item)=>{
console.log( pop(item.type,item.content,item.color));
})
data.forEach((item)=>{
console.log(new pop(item.type,item.content,item.color));
})
//jquery
(function(){
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
}
jQuery.fn=jQuery.prototype={
init:function(){
}
}
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function() {
}
jQuery.extend({
});
window.$=jquery;
})()
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
89
90
91
92
93
94
95
96
97
98
99
100
101
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
89
90
91
92
93
94
95
96
97
98
99
100
101
# 建造者模式
- 目的:需要组合出一个全局对象
- 场景:当要创建单个,庞大的组合对象时
//定义最终类
function Editor(){
}
//html初始模块
function initHtml(domStyle){
this.template='<div style={{editorStyle}}><div></div><div><textarea style={{areaSyle}}/></div></div>';
}
initHtml.prototype.initStyle=function(){
}
initHtml.prototype.renderDom=function(){
}
//字体颜色,大小控制
function fontControll(){
};
fontControll.prototype.changeColor=function(){
}
fontControll.prototype.changeFontsize=function(){
}
//回滚
function stateControll(){
}
stateControll.prototype.saveState=function(){
}
stateControll.prototype.stateBack=function(){
}
stateControll.prototype.stateGo=function(){
}
window.Editor=Editor;
function Vue (options) {
if (!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword');
}
this._init(options);
}
initMixin(Vue);
stateMixin(Vue);
eventsMixin(Vue);
lifecycleMixin(Vue);
renderMixin(Vue);
export function install (_Vue) {
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== 'production') {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
}
return
}
Vue = _Vue
applyMixin(Vue)
}
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
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
# 单例模式
- 目的:确保全局对象只有一个
- 场景: 为了避免重复新建, 避免多个对象存在互相干扰
//vue
function store(){
this.store={
}
if(store.install){
return store.install;
}
store.install=this;
}
store.install=null;
//vue-router
let _Vue;
function install (_Vue) {
if (install.installed && _Vue === Vue) return
install.installed = true
_Vue = Vue
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 提高可复用性
- 对象可以再重新使用, 不用修改
- 重复代码少
- 模块功能单一
# 桥接模式
- 目的:减少耦合
- 场景: 减少模块之间的耦合
//menu1,menu2,menu3
/*function menuItem(word){
this.word="";
this.dom=document.createElement('div');
this.dom.innerHTML=this.word;
}
var menu1=new menuItem('menu1');
var menu2=new menuItem('menu2');
var menu3=new menuItem('menu3');
menu1.onmouseover=function(){
menu1.style.color='red';
}
menu2.onmouseover=function(){
menu1.style.color='green';
}
menu3.onmouseover=function(){
menu1.style.color='blue';
}
menu1.onmouseout=function(){
menu1.style.color='white';
}
menu2.onmouseout=function(){
menu1.style.color='white';
}
menu3.onmouseout=function(){
menu1.style.color='white';
}*/
function menuItem(word,color){
this.word=word;
this.color=color;
this.dom=document.createElement('div');
this.dom.innerHTML=this.word;
document.getElementById('app').appendChild(this.dom);
}
menuItem.prototype.bind=function(){
var self=this;
this.dom.onmouseover=function(){
console.log(self.color);
this.style.color=self.color.colorOver;
}
this.dom.onmouseout=function(){
this.style.color=self.color.colorOut;
}
}
function menuColor(colorover,colorout){
this.colorOver=colorover;
this.colorOut=colorout;
}
var data=[{word:'menu1',color:['red','black']},{word:'menu2',color:['green','black']},{word:'menu3',color:['blue','black']}]
for(var i=0;i<data.length;i++){
new menuItem(data[i].word,new menuColor(data[i].color[0],data[i].color[1])).bind();
}
//express
var methods=['get','post','delete','put'];
methods.forEach(function(method){
app[method]=function(){
route[method].apply(route,slice.call(arguments,1))
}
})
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
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
# 享元模式
- 目的: 减少对象/代码数量
- 场景: 当代码中创建了大量类似对象和类似的代码块
//文件上传
function uploader(fileType,file){
this.fileType=fileType;
this.file=file;
}
uploader.prototype.init=function(){
//初始化文件上传的html
}
uploader.prototype.delete=function(){
//删除掉该html
}
uploader.prototype.uploading=function(){
//上传
}
var fileob1,fileob2,fileob3,fileob4
var data=[
{
type:'img',
file:fileob1
},
{
type:'txt',
file:fileob2
},
{
type:'img',
file:fileob3
},
{
type:'word',
file:fileob4
},
]
for(var i=0;i<data.length;i++){
new uploader(data[i].type,data[i].file);
};
//fileType,file
function uploader(){
}
uploader.prototype.init=function(){
//初始化文件上传的html
}
uploader.prototype.delete=function(){
//删除掉该html
}
uploader.prototype.uploading=function(filetype,file){
}
var uploader=new uploader();
for(var i=0;i<data.length;i++){
uploader.uploading(data[i].type,data[i].file);
}
//extends
var jQuery={};
jQuery.fn={};
jQuery.extend = jQuery.fn.extend = function() {
/* if(arguments.length==1){
for(var item in arguments[0]){
this[item]=arguments[0][item]
}
}else if(arguments.length==2){
for(var item in arguments[1]){
arguments[0][item]=arguments[1][item]
}
return arguments[0];
}*/
var target=arguments[0];
var source;
if(arguments.length==1){
target=this;
source=arguments[0];
}else if(arguments.length==2){
target=arguments[0];
source=arguments[1];
}
for(var item in source){
target[item]=source[item]
}
return target;
}
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
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
# 模板方法
- 目的: 定义一系列操作的骨架,简化后面类似操作的内容
- 场景: 当场景中出现类似操作的内容
function basePop(word,size){
this.word=word;
this.size=size;
this.dom=null;
}
basePop.prototype.init=function(){
var div=document.createElement('div');
div.innerHTML=this.word;
div.style.width=this.size.width+'px';
div.style.height=this.size.height+'px';
this.dom=div;
}
basePop.prototype.hidden=function(){
//定义基础操作
this.dom.style.display='none';
}
basePop.prototype.confirm=function(){
//定义基础操作
this.dom.style.display='none';
}
function ajaxPop(word,size){
basePop.call(this,word,size);
}
ajaxPop.prototype=new basePop();
var hidden=ajaxPop.prototype.hidden;
ajaxPop.prototype.hidden=function(){
hidden.call(this);
console.log(1);
}
var confirm=ajaxPop.prototype.confirm;
ajaxPop.prototype.confirm=function(){
confirm.call(this);
console.log(1);
}
var pop=new ajaxPop('sendmes',{width:100,height:300});
pop.init();
pop.confirm();
var axios={get:function(){
return Promise.resolve();
}};
//算法计算器
function counter(){
this.beforeCounter=[];
this.afterCounter=[];
}
//然后我们把具体的不同部分留到具体使用的时候去扩展
//所以我们定义两个方法来扩展
counter.prototype.addBefore=function(fn){
this.beforeCounter.push(fn);
}
counter.prototype.addAfter=function(fn){
this.afterCounter.push(fn);
}
//最终计算方法
counter.prototype.count=function(num){
//结果边两
var _resultnum=num;
//算法队列数组组装
var _arr=[baseCount];
_arr=this.beforeCounter.concat(_arr);
_arr=_arr.concat(this.afterCounter);
//不同部分的相同算法骨架
function baseCount(num){
num+=4;
num*=2;
return num;
}
//循环执行算法队列
while(_arr.length>0){
_resultnum=_arr.shift()(_resultnum);
}
return _resultnum;
}
//使用
var countObject=new counter();
countObject.addBefore(function(num){
num--;
return num;
})
countObject.addAfter(function(num){
num*=2;
return num;
})
countObject.count(10);
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
89
90
91
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
89
90
91
← 发布/订阅模式
