/**
* 发布订阅者模式实现proxy数据劫持(vue)(TypeScript版)
*/
interface Publish {
register(eventName : string, sub : Subscribe) : void;//注册订阅者
remove(eventName : string, sub ?: Subscribe) : void;//移出订阅者
notify(eventName : string,obj: object) : void;//发布
}
interface SubscribesObj {
[key : string] : Array<Subscribe>;
}
/**
*订阅者和发布者管理平台,负责注册,发布和删除管理的实现
*/
class PublishImpl implements Publish{
public subList : SubscribesObj;
constructor(){
this.subList = {};
}
notify(eventName: string,obj: object): void {
const s = this.subList[eventName];
if(s){
s.forEach(x=>{
x.update(obj)
})
}
}
register(eventName: string, sub: Subscribe): void {
if(!this.subList[eventName]){
this.subList[eventName] = [];
}
this.subList[eventName].push(sub);
}
remove(eventName: string, sub?: Subscribe): void {
const s = this.subList[eventName];
if(!sub){
delete this.subList[eventName];
} else {
for(let i=0; i<s.length;i++){
if(sub === s[i]){
s.splice(i,1);
}
}
}
}
}
/**
* 订阅者实现方法,也就是订阅内容
*/
interface Subscribe {
update(obj: object) : void;
}
/**
* 实例化订阅者操作
*/
class SubscribeImpl1 implements Subscribe{
update(obj: object) : void{
console.log(obj);
}
}
function isObject(target) {
return typeof target === 'object' && target !== null
}
function main():void{
const pub = new PublishImpl();
const s1 = new SubscribeImpl1();
pub.register('1',s1);//实例化并且注册
/**
* proxy代理目标对象,如果set则执行发布,get其实利用递归的形式,因为新增属性和
* 数组变化是调用get方法然后再调用set方法,所以递归之。
*/
let proxy = target => new Proxy(target,{
get(target:object,p:string,receiver:object){
let res = Reflect.get(target, p, receiver)
return isObject(res) ? proxy(res) : res
},
set(target:object,p:string,v:string,receiver:object){
let result = Reflect.set(target,p,v,receiver);
//执行发布
pub.notify('1',target);
return result;
}
});
let obj = proxy({
name:'张三',
age:28,
arr:[1,2,3]
});
obj.name = "zhuhong";
obj.ss = "dd";
obj.arr.push(4);//两部操作,lengh和push(4),所以会输出两遍
}
main();
