Proxy 是 JavaScript 2015 的一个新特性。Proxy 的代理是针对整个对象的,而不是对象的某个属性
,因此不同于 Object.defineProperty 的必须遍历对象每个属性,Proxy 只需要做一层代理就可以监听同级结构下的所有属性变化,当然对于深层结构,递归还是需要进行的。此外**Proxy支持代理数组的变化。
/* based on proxy */
// 使用 Proxy 时需要定义一个代理对象 handler 来对目标进行代理操作,
// 这个对象主要有两个方法,即 get 和 set,
// 分别为 获取和设置属性值的时候触发。同时在内部的实现需要利用到 Reflect对象
//
//
// 首先明确 reactive 函数接收一个参数,
// 需要对这个参数进行代理,并返回代理后的结果。
// 如果参数是对象才需要代理,否则直接返回。
// 定义一个缓存对象
const toProxy = new WeakMap(); // 保存代理后的对象
/* 返回一个被代理后的结果,通过操作这个结果可以来实现响应式, 例如视图更新 */
function reactive(target) {
// 如果是个对象,则返回被代理后的结果,如果不是则直接返回
if(!isObject(target)) {
return target;
}
if(toProxy.get(target)) { // 判断对象是否已经被代理了
return toProxy.get(target);
}
const handler = {
get(target, key, receiver) {
const proxyTarget = Reflect.get(target, key, receiver);
// 相当于 return target[key]
if(isObject(target[key])) {
return reactive(proxyTarget);
}
return proxyTarget;
},
set(target, key, value, receiver) {
// 只对私有属性的修改动作触发视图更新
if(!target.hasOwnProperty(key)) {
trigger();
}
return Reflect.set(target, key, value, receiver);
// 相当于 target[key] = value
}
};
// 利用 Proxy 来代理这个对象属性
let observed = new Proxy(target, handler);
toProxy.set(target, observed); // 保存已代理的对象
return observed;
}
// 提示视图需要更新
function trigger() {
console.log('视图需要更新');
}
function isObject(param) {
return typeof param === 'object' && param !== null;
}