Proxy从ES6到VUE3.0
ES6-Proxy代理
Vue3.0-Proxy
感兴趣的可以去看一下,我这里只记录一下我面试遇到的
vue双向绑定的原理 v-module
vue数据双向绑定通过‘数据劫持’:指的是在访问或者修改对象的某个 属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结 果 。 vue2.0用 Object.defineProperty() 这个方法重新定义了对象 获取属性值(get)和设置属性值(set)的操作来实现的
vue3.0用Proxy
- 订阅发布模式实现
首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。
因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。
接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令(如v-model,v-on)对应初始化成一个订阅者Watcher,
并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图
function type(name){
this.name = name;
this.readers = [];//定义一个容器,来放谁订阅了
this.subscription = function(p){
this.readers.push(p);
}
this.unsubscribe= function(p) {
let index = this.readers.findIndex(person=>{
return person == p;
})
this.readers.splice(index,1);//移除这个人
}
this.publish = function(){//遍历这个数组,给每个人发消息
this.readers.forEach(p => {
p.notice(this.name+"的新消息"+Math.random());
})
}
}
function Person(name) {//实例对象人的构造函数
this.name = name;//获取人的名字
this.notice = function(msg){//注意有消息过来了
console.log(this.name+ "收到了 "+ msg);
}
}
let event = new type("抖音");
let zhangsan = new Person("zhangsan");
let lisi = new Person("lisi");
let wangwu = new Person("wangwu");
event.subscription(wangwu)//王五订阅
event.subscription(lisi)//李四订阅
event.unsubscribe(lisi)//李四退订
event.publish();//公布
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该 对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对 外界的访问进行过滤和改写。
proxy
如果需要实现一个 Vue 中的响应式,需要我们在 get 中收集依赖,在 set 派发更新,之所以 Vue3.0 要使用 Proxy 替换原本的 API 原因在 于 Proxy 无需一层层递归为每个属性添加代理,一次即可完成以上操 作,性能上更好,并且原本的实现有一些数据更新不能监听到,但是 Proxy 可以完美监听到任何方式的数据改变,唯一缺陷可能就是浏览器 的兼容性不好了
let obj = { a: 1 };
let getLogger = (target, key) => {
console.log(`'${key}' = ${target[key]}`);
};
let setBind = (value, key) => {
console.log(`监听到属性${key}改变为${value}`);
};
let handler = {
get(target, key, value) {
getLogger(target, key);
return Reflect.get(target, key, value);
},
set(target, key, value, receiver) {
setBind(value, key);
return Reflect.set(target, key, value);
}
};
let proxy = new Proxy(obj, handler);
proxy.a = 2;
console.log(proxy.a);