Skip to content

Commit f9beeec

Browse files
committed
看书练习备忘
1 parent 7f14a09 commit f9beeec

File tree

1 file changed

+197
-0
lines changed

1 file changed

+197
-0
lines changed

memo/发布订阅模式.js

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/************ 模块定义 ************/
2+
3+
var Event = (function () {
4+
5+
var Event,
6+
_default = 'default'; // 默认值
7+
Event = (function () {
8+
var _listen,
9+
_trigger,
10+
_remove,
11+
_shift = Array.prototype.shift,
12+
_unshift = Array.prototype.unshift,
13+
namespaceCache = {},
14+
_create,
15+
each = function (ary, fn) {
16+
var ret;
17+
for (var i = 0, l = ary.length; i < l; i++) {
18+
var n = ary[i];
19+
ret = fn.call(n, i, n);
20+
}
21+
return ret;
22+
};
23+
24+
// 推入订阅的事件栈
25+
_listen = function (key, fn, cache) {
26+
27+
// 无该事件的订阅则创建
28+
if (!cache[key]) {
29+
cache[key] = [];
30+
}
31+
32+
// 推入
33+
cache[key].push(fn);
34+
35+
//注意:cache是对象,对象参数是对象的一个引用,内部修改是会影响到外面的
36+
};
37+
38+
// 移除订阅
39+
_remove = function (key, cache, fn) {
40+
if (cache[key]) {
41+
/*
42+
* 判断有无传函数
43+
* 有:移除事件栈中的该函数
44+
* 无:移除事件栈中所有的函数
45+
* */
46+
if (fn) {
47+
for (var i = cache[key].length; i >= 0; i--) {
48+
if (cache[key] === fn) {
49+
cache[key].splice(i, 1);
50+
}
51+
}
52+
} else {
53+
cache[key] = [];
54+
}
55+
}
56+
};
57+
58+
// 发布订阅
59+
_trigger = function () {
60+
var cache = _shift.call(arguments), // 获取事件栈
61+
key = _shift.call(arguments), // 获取事件名
62+
args = arguments, // 获取发布时的传参
63+
_self = this, // 指向函数最后return出的对象,模块接口
64+
stack = cache[key]; // 事件栈中对应该事件名的所有函数
65+
66+
if (!stack || !stack.length) {
67+
return;
68+
}
69+
70+
71+
// 遍历事件栈中对应该事件名的所有函数,并在模块接口对象的环境下执行
72+
return each(stack, function () {
73+
return this.apply(_self, args);
74+
});
75+
};
76+
77+
// 传入事件的命名空间名,返回模块api
78+
_create = function (namespace) {
79+
var namespace = namespace || _default;
80+
var cache = {},
81+
offlineStack = [], // 存储已经发布的函数栈
82+
ret = {
83+
listen: function (key, fn, last) {
84+
// 创建监听
85+
_listen(key, fn, cache);
86+
87+
// 后面的逻辑都是处理先发布后订阅的离线事件,如果没有则直接return跳出
88+
if (offlineStack === null) {
89+
return;
90+
}
91+
92+
// 根据last是否为'last'决定是只拿最后一个函数,还是遍历执行所有已发布的函数
93+
if (last === 'last') {
94+
offlineStack.length && offlineStack.pop()();
95+
} else {
96+
each(offlineStack, function () {
97+
this();
98+
});
99+
}
100+
101+
// 结束以后置空
102+
offlineStack = null;
103+
},
104+
one: function (key, fn, last) {
105+
106+
// 移除所有同名事件
107+
_remove(key, cache, fn);
108+
109+
// 重新创建监听
110+
this.listen(key, fn, last);
111+
},
112+
remove: function (key, fn) {
113+
// 移除指定事件
114+
_remove(key, cache, fn);
115+
},
116+
trigger: function () {
117+
var fn,
118+
args,
119+
_self = this; // 指向模块返回api的对象
120+
121+
_unshift.call(arguments, cache); // 把订阅函数栈也添加到参数集合中,便于模块内部调用时获取
122+
args = arguments;
123+
124+
fn = function () {
125+
return _trigger.apply(_self, args);
126+
};
127+
128+
// 如果offlineStack不为空,则把发布推入发布函数栈
129+
if (offlineStack) {
130+
return offlineStack.push(fn);
131+
}
132+
return fn();
133+
}
134+
};
135+
136+
//判断是否传了命名空间,一般情况都为true,因为默认的命名空间是'default',是有值的
137+
return namespace ? (namespaceCache[namespace] ? namespaceCache[namespace] : namespaceCache[namespace] = ret) : ret;
138+
};
139+
140+
return {
141+
create: _create,
142+
one: function (key, fn, last) {
143+
var event = this.create();
144+
event.one(key, fn, last);
145+
},
146+
remove: function (key, fn) {
147+
var event = this.create();
148+
event.remove(key, fn);
149+
},
150+
listen: function (key, fn, last) {
151+
var event = this.create();
152+
event.listen(key, fn, last);
153+
},
154+
trigger: function () {
155+
var event = this.create();
156+
event.trigger.apply(this, arguments);
157+
}
158+
}
159+
}());
160+
161+
return Event;
162+
}());
163+
164+
/************ 先发布后订阅 ************/
165+
166+
Event.trigger('click', 5);
167+
Event.trigger('click', 6);
168+
Event.listen('click', function (a) {
169+
console.log(a); // 输出:5
170+
});
171+
172+
Event.listen('click', function (a) {
173+
console.log(a + 1); // 输出:5
174+
});
175+
Event.listen('click', function (a) {
176+
console.log(a + 2); // 输出:5
177+
});
178+
Event.trigger('click', 0);
179+
180+
console.log('*************************************');
181+
182+
/************ 使用命名空间 ************/
183+
184+
Event.create('namespace1').listen('click', function (a) {
185+
console.log(a); // 输出:1
186+
});
187+
Event.create('namespace1').listen('click', function (a) {
188+
console.log(a + 1); // 输出:2
189+
});
190+
191+
Event.create('namespace1').trigger('click', 1);
192+
193+
Event.create('namespace2').listen('click', function (a) {
194+
console.log(a); // 输出:2
195+
});
196+
197+
Event.create('namespace2').trigger('click', 20);

0 commit comments

Comments
 (0)