编码中常用的场景:发布订阅模式:也称作观察者模式,定义对象间的一对多的依赖关系,当一个对象的状态发 生改变 时,所有依赖于它的对象都将得到通知;
//订阅事件
window.addEventListener('click',()=>{
alert("监听到某事件")
})
//发布事件
window.click()
举个例子:B是天气预报中心,用户A想从B处获取天气预报;A就要将自己的联系方式储存到B处,当天气预报更新以后,B发送天气信息给A; 此处:存储就相当于 订阅;发信息就相当于发布;
代码实现如下:
var observer = {
//订阅集合
subscribes:[],
//订阅
subscribe:function(type,fn){
if(!this.subscribes[type]){
this.subscribes[type] = [];
}
//收集订阅者的处理
typeof fn === 'function' && this.subscribes[type].push(fn);
},
//发布 可能会携带一些信息发布出去
publish: function(){
var type = [].shift.call(arguments),
fns = this.subscribes[type];
//不存在订阅类型,以及订阅时未传入处理回调的
if(!fns || !fns.length){
return;
}
//遍历处理调用
for(var i = 0;i<fns.length;++i){
fns[i].apply(this,arguments);
}
},
//删除订阅
remove:function(type,fn){
//删除全部
if(typeof type === 'undefined'){
this.subscribes = [];
return;
}
var fns = this.subscribes[type];
//不存在的订阅类型,以及订阅时未传入处理回调的
if(!fns || !fns.length){
return;
}
if(typeof fn === 'undefined'){
fns.length = 0;
return;
}
//挨个处理删除
for(var i = 0;i<fns.length;++i){
if(fns[i] === fn){
fns.splice(i,1)
}
}
}
}
订阅-发布:
//订阅事件
observer.subscribe('Atemp',function(temp){
console.log("获取的当前温度为:"+ temp +'℃')
})
//发布事件
observer.publish('Atemp',18)
Vue中使用:
vue中实现数据双向绑定:数据监听 + 订阅发布者模式(观察者模式);
class Vue{
constructor(options) {
this.$options = options;
// 数据响应化
this.$data = options.data;
this.observe(this.$data);
}
//判断data是否是对象,是对象则遍历
observe(value) {
if (!value || typeof value !== "object") {
return;
}
// 遍历该对象
Object.keys(value).forEach(key => {
this.defineReactive(value, key, value[key]);
});
}
//数据监听
defineReactive(obj, key, val) {
//递归解决数据嵌套
this.observe(val);
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
//为每个属性添加依赖,订阅
Dep.target && dep.addDep(Dep.target);
return val;
},
set(newVal) {
if (newVal === val) {
return;
}
val = newVal;
//发布事件,触发更新节点
dep.notify();
}
});
}
// Dep:用来管理watcher
class Dep {
constructor() {
// 这里存放每个依赖的1个或多个watcher
this.deps = [];
}
// 在deps中添加一个监听器对象
addDep(dep) {
this.deps.push(dep);
}
// 通知所有依赖去更新视图
notify() {
this.deps.forEach(dep => dep.update());
}
}
//Watcher 监听器
class Watcher {
constructor(vm, key, cb) {
this.vm = vm;
this.key = key;
this.cb = cb;
// 将当前watcher实例指定到Dep静态属性target
Dep.target = this;
this.vm[this.key]; // 触发getter,添加依赖
Dep.target = null;
}
update() {
console.log("属性更新了");
//执行new Watcher传递过来的回调函数,即data值改变时,需要执行的函数。
this.cb.call(this.vm, this.vm[this.key]);
}
}
}