工具-观察者模式实现on/trigger结构模型
最近在疯狂的补习js设计模式相关的内容,并且整理了一个系列更文,里面好多demo都是借鉴过来的,自己真正懂了多少还是需要自己去思考设计一个模型出来才能检验一下。
jQuery 中的 on 和 trigger 相信大家都不陌生:
$(selector).on(event:string, function(){})
$(selector).trigger(event:string)
这个方法曾经帮助我实现了很多个html页面,原来只是在用,如今又回过头来看了一下js设计模式中的观察者模式或者说发布订阅模式之后,感觉我可以模拟一个出来,具体用来干嘛还没想好,放在后面的思维扩散里面发散一下吧!
实现过程
废话少说,直接上代码:
class OnClass {
constructor(name) {
this.name = name;
}
on(e, fn) {
if (!this[e]) {
console.log("OnClass.on.e ::", e);
this[e] = fn.bind(this);
console.log("OnClass.on.this ::", this);
} else {
throw e + " 已经存在,不可再次绑定!";
}
}
remove(e) {
delete this[e];
}
trigger(e, ...args) {
console.log("OnClass.trigger.this ::", this);
console.log("OnClass.trigger.e ::", e);
console.log("OnClass.trigger.args ::", args);
console.log("OnClass.trigger.this[e] ::", this[e]);
return this[e]();
}
}
class User extends OnClass {
constructor(name) {
super(name);
}
}
const Bob = new User("Bob");
// 绑定 on 的时候 不能用 箭头函数
Bob.on("say", function () {
console.log(this);
console.log("i'm", this.name, ".");
});
Bob.trigger("say");
Bob.remove("say");
Bob.on("say", function () {
console.log(this);
});
Bob.trigger("say");
如上代码所示,我声明了一个 OnClass 的基础类,里面绑定了 3 个方法:
- on:用来搜集绑定的事件名称及具体回调方法
- trigger:用来触发已经绑定的方法
- remove:移除已经被绑定的方法
并且做了一些简单的处理,如果已经绑定了同名的方法,不能再次绑定。
然后声明了一个实际的业务类,继承自 OnClass,这样这个业务类就拥有了上面的三个方法。并且可以有自己的私有方法。其实一开始我没有做这样的结构,但是考虑到代码的复用性,所以就拆开了。
通过执行这个脚本:
或者触发重复绑定:
我们可以看到控制台打印的这些内容,和我们预料的是一样的。
解释
其实代码很简单,在执行 on 方法的时候,我们把 on 里面的 event 直接绑定在 this 上,通过 bind 方法返回一个方法并将 this 指向指回 this。
这样就可以使用 this[event] 或者 trigger 的方式去触发被 on 绑定的方法了。
只是和 jQuery 中的不一样的是,我们的方法几乎全部都是自定义的方法,也就是说,即便绑定了 click
事件,也是没有用的,因为首先 this 不是 dom 对象,然后 这个 click 事件也不是鼠标的 click 事件。
发散
那么这个东西有啥用呢?分两个方向说吧。
仅仅站在这套代码的角度:
- 在项目中都封装过 axios 吧?是不是可以把所有的请求都通过 on 的方式挂载在 axios 上,如果需要卸载的话就可以使用 remove 卸载掉,而不是去频繁的修改一个 js 文件?这也是 现阶段 composition API 推荐的方式。
- 项目中某个业务对象,例如 User ,使用这个模型给他添加一些私有方法,很灵活。一处挂载,任何使用的地方都可以调用。
- 避免一个对象变成一个大象去频繁的维护它。
把这套代码看成一个模型的话就也很有意思,可以将它看成一个搜集器,类似于 vuex 一样的工具类,对于脱离vue框架的项目来说,这就是一个 vuex 。
总结
我并没有去查阅 jQuery 中的 on 和 trigger 的源码是怎么实现的,只是从使用者的角度来尝试着去模拟一个同样等功能的模型出来。
这段代码只代表了一种思路,并不是一个固定的使用方式,但是有了这个思路,很多复杂的场景都可以使用这样的方法去构建出一个新的模型出来。有了这种想法,在编码的过程中就不会着眼于当前业务,而是会考虑更多,让自己的代码更加健全,高内聚低耦合,自动化,工程化...
设计模式还是很有意思的,每看一次都会有不一样的想法。
转载自:https://juejin.cn/post/7179803081402974264