vue作为前端使用广泛的三大框架(react、vue、Angular)之一,研究vue3的源码认识vue3如何使用proxy做双向数据绑定的。
1、proxy代理概述
proxy是ES6新增对象,用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等); proxy在目标对象的外层搭建一层拦截,外界对目标对象的某些操作,必须通过这层拦截。
var p=new Proxy(target, handler);
// target 目标对象 (可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
// handler 一个对象 其属性是(当执行一个操作时定义代理的行为的函数)。
new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为
proxy可以直接代理对象并且返回一个新对象,而不像Object.defineProperty()劫持对象的属性,需要遍历 对象的每个属性,如新增属性时,需要重新遍历对象,对其新增属性再使用Object.defineProperty进行劫持。
const obj={name:'peak'};
const p = new Proxy(obj, {
get:(target, key, receiver)=>{
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set:(target, key, value, receiver)=>{
console.log(target, key, value, receiver);
return Reflect.set(target, key, value, receiver);
}
});
p.name //'peak' 'getting name' 触发get方法
p.age=18 //触发set方法
Proxy支持13种拦截操作
- get(target, propKey, receiver) 拦截对象属性的读取 比如p.age,p[age];
- set(target, propKey, receiver) 拦截对象属性的设置 比如 p.age=18,返回一个布尔值
- has(target, propKey) 拦截 propKey in proxy 的操作,返回一个布尔值。
- deleteProperty(target, propKey) 拦截删除属性 delete proxy[foo] 和 delete proxy.foo 以及Reflect.deleteProperty() 返回一个布尔值 更多拦截操作说明
2、Reflect
Reflect是内置对象,为操作对象而提供的新API,将Object对象的属于语言内部的方法放到Reflect对象上,即从Reflect对象上拿Object对象内部方法。 将用 老Object方法 报错的情况,改为返回false
//老写法
try {
Object.defineProperty(target, property, attributes);
// success
} catch (e) {
// failure
}
'name' in Object //true
//新写法
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}
Reflect.has(Object,'name') //true
Reflect与Proxy是相辅相成的,在Proxy上有的方法,在Reflect就一定有