欢迎在下方发表您的优质见解
// 发布订阅中心, on-订阅, off取消订阅, emit发布, 内部需要一个单独事件中心caches进行存储;
interface CacheProps {
[key: string]: Array<((data?: unknown) => void)>;
}
class Observer {
private caches: CacheProps = {}; // 事件中心
on (eventName: string, fn: (data?: unknown) => void){ // eventName事件名-独一无二, fn订阅后执行的自定义行为
this.caches[eventName] = this.caches[eventName] || [];
this.caches[eventName].push(fn);
}
emit (eventName: string, data?: unknown) { // 发布 => 将订阅的事件进行统一执行
if (this.caches[eventName]) {
this.caches[eventName].forEach((fn: (data?: unknown) => void) => fn(data));
}
}
off (eventName: string, fn?: (data?: unknown) => void) { // 取消订阅 => 若fn不传, 直接取消该事件所有订阅信息
if (this.caches[eventName]) {
const newCaches = fn ? this.caches[eventName].filter(e => e !== fn) : [];
this.caches[eventName] = newCaches;
}
}
}
class EventListener {
listeners = {};
on(name, fn) {
(this.listeners[name] || (this.listeners[name] = [])).push(fn)
}
once(name, fn) {
let tem = (...args) => {
this.removeListener(name, fn)
fn(...args)
}
fn.fn = tem
this.on(name, tem)
}
removeListener(name, fn) {
if (this.listeners[name]) {
this.listeners[name] = this.listeners[name].filter(listener => (listener != fn && listener != fn.fn))
}
}
removeAllListeners(name) {
if (name && this.listeners[name]) delete this.listeners[name]
this.listeners = {}
}
emit(name, ...args) {
if (this.listeners[name]) {
this.listeners[name].forEach(fn => fn.call(this, ...args))
}
}
}
function deepclone(){
type of (obj)!='object ‘ || obj==null
}
function Events() {
this.eventHub = {}
}
Events.prototype.$on = function(eventName, fn) {
this.eventHub[eventName] = (this.eventHub[eventName] || []).concat(fn)
}
Events.prototype.$emit = function(eventName, args) {
if (this.eventHub[eventName]) {
this.eventHub[eventName].forEach((fn) => {
fn(args)
})
}
}
Events.prototype.$off = function(eventName, fn) {
if (this.eventHub[eventName]) {
if (!fn) {
this.eventHub[eventName] = []
} else {
this.eventHub[eventName] = this.eventHub[eventName].filter(fun => fun !== fn)
}
}
}
Events.prototype.$once = function(eventName, fn) {
const fun = (...args) => {
fn.apply(this, args)
this.$off(eventName, fn)
}
this.$on(eventName, fun)
}
function test(a) {
console.log(a)
}
var event = new Events()
event.$once('test', test)
event.$emit('test', 1)
class EventEmitter {
constructor(){
this.events = {};
}
on(event, callback){
const callbacks = this.events[event] || [];
if(Array.isArray(callbacks)) {
callbacks.push(callback);
this.events[event] = callbacks;
}
return this;
}
off(event, callback){
const callbacks = (this.events[event] || []).filter(cb => cb !== callback);
this.events[event] = callbacks;
return this;
}
once(event, callback){
const wrap = (...args) => {
typeof callback === 'function' && callback.apply(this, args);;
this.off(event, wrap);
}
this.on(event, wrap);
return this;
}
emit(event) {
const callbacks = this.events[event] || [];
if(Array.isArray(callbacks)) {
callbacks.forEach(cb => typeof cb === 'function' && cb());
}
return this;
}
}
const eventEmitter = new EventEmitter();
eventEmitter.on('click', () => {
console.log('click 1')
})
eventEmitter.on('click', () => {
console.log('click 2')
})
// eventEmitter.off('click')
eventEmitter.emit('click')
eventEmitter.once('click')
console.log(eventEmitter);
click 1
click 2
EventEmitter {
events: { click: [ [Function], [Function], [Function: wrap] ] } }
class Observer {
static events = new Map()
static on(name, fn) {
this.events.set(name, {isOnce: false, fn})
}
static once(name, fn) {
this.events.set(name, {isOnce: true, fn})
}
static off(name) {
this.events.delete(name)
}
static emit(name, data) {
let cache = this.events.get(name)
if (cache) {
if (cache.isOnce) this.events.delete(name)
cache.fn(data)
}
}
}
class EventBus {
listeners = [];
on(name, fn) {
const listener = {
name,
fn,
isOnce: false,
};
this.listeners.push(listener);
return listener;
}
once(name, fn) {
const listener = {
name,
fn,
isOnce: true,
};
this.listeners.push(listener);
return listener;
}
off(listener) {
const index = this.listeners.findIndex(lst => lst === listener);
if (index > -1) {
this.listeners.splice(index, 1);
}
}
emit(name, data) {
for (const listener of this.listeners) {
if (listener.name === name) {
try {
if (listener.isOnce) this.off(listener);
listener.fn(data);
} catch (error) {
console.error('bus emit error', error);
}
}
}
}
}
const test = new EventBus();
const test1 = test.on('console', () => console.log('123'));
const test2 = test.on('console', () => console.log('456'));
const test3 = test.once('console', () => console.log('789'));
// 第一次
test.emit('console', null);
// 123
// 456
// 789
// 第二次
test.emit('console', null);
// 123
// 456
// 第三次
test.off(test2);
test.emit('console', null);
// 123
熟写发布订阅模式可以锻炼你的增删改查能力
class PubSub {
sid = 0
topicList = {}
constructor(...tops) {
this.topicList = Object.fromEntries(tops.map(item => [item, []]));
}
isValidTopic(topic){
return Object.keys(this.topicList).includes(topic)
}
sub(topic, target) {
const isValidTopic = this.isValidTopic(topic);
if(isValidTopic){
target.id = ++this.sid;
target[Symbol.for('update')] = function(cb) {
cb();
}
this.topicList[topic].push(target);
}
}
pub(topic, cb) {
const isValidTopic = this.isValidTopic(topic);
if(isValidTopic){
this.topicList[topic].forEach(o => {
o[Symbol.for('update')](cb);
})
}
}
unsub(topic, target) {
const isValidTopic = this.isValidTopic(topic);
if(isValidTopic){
const i = this.topicList[topic].findIndex(o => o.id == target.id);
if(i != -1) {
this.topicList[topic].splice(i, 1);
}
}
}
}
const pb = new PubSub('china', 'america');
const o1 = {};
const o2 = {};
pb.sub('china', o1);
pb.sub('america', o2);
pb.pub('america', () => {
console.log('对你实施制裁!!!');
})
pb.pub('china', () => {
console.log('强烈反对!!!');
})
pb.unsub('china', o1);
pb.unsub('america', o2);
console.log(pb.topicList);
Most helpful comment
function deepclone(){
type of (obj)!='object ‘ || obj==null
}