Proxy是什么
proxy用于创建一个对象的代理,并可以监听该代理对象的相关操作。比如:访问该代理对象的某个属性,会触发get方法,给代理对象的某个属性赋值,会触发set方法。 Proxy接受两个参数,一个是源对象,一个是捕捉器,如下:
const personInfo = {
name: '张三',
age: 18
};
const proxy = new Proxy(personInfo, {
get(target, key) {
console.log('2222222', key) // name(proxy.name代表访问了代理对象的name属性,会触发get方法)
return target[key];
},
set(target, key, value) {
target[key] = value;
}
});
console.log(proxy.name); // 张三
上面代码proxy是personInfo的代理对象,当我们访问proxy的name属性时,会触发get方法
const personInfo = {
name: '张三',
age: 18
};
const proxy = new Proxy(personInfo, {
get(target, key) {
console.log('2222222', key) // name(proxy.name代表访问了代理对象的name属性,会触发get方法)
return target[key];
},
set(target, key, value) {
console.log(key, value); // name 李四
target[key] = value;
}
});
proxy.name = '李四';
console.log(proxy.name, personInfo) // 李四 李四
上面代码给proxy的name属性赋值,会触发set方法,从而改变源对象的值。其实代理的对象proxy某种意义上来讲就是源对象的拷贝,所以改变target的name属性,proxy的name属性也跟着改变了。但是这会有一个问题,我们改变或者访问的是proxy的值,意味着其实我们想要操作的对象是proxy,而上面代码操作的却是源对象target。这样在一些情境下会产生bug,如下:
const personInfo = {
name: '张三',
age: 18,
get value() {
console.log(this) // 这时this指的是源对象personInfo,而不是proxy,因为在proxy.value触发get方法时,访问的是target(源对象)这显然是不准确的
return this.name
}
};
const proxy = new Proxy(personInfo, {
get(target, key) {
console.log(key) // 只打印一次key,值为value
return target[key]
},
set(target, key, value) {
target[key] = value;
}
});
console.log(proxy.value)
以上代码,在proxy.value的时候,其实是要触发两次get方法的,因为this.name也需要触发get方法的,但是因为在第一次触发get的时候,操作的的target源对象,所以this.name不会触发get方法,所以只答应了一次。正确写法如下:
// 源对象
const personInfo = {
name: '张三',
age: 18,
get value() {
console.log(this) // 这时this指的是代理对象proxy
return this.name
}
};
const proxy = new Proxy(personInfo, {
get(target, key, receiver) { // receiver:这里表示代理对象proxy
console.log(key); // 打印两次,第一次为value,第二次为name
return Reflect.get(target, key, receiver); // Reflect表示反射
},
set(target, key, value) {
const result = Reflect.set(target, key, value, receiver);
return result;
}
});
console.log(proxy.value)
以上代码,proxy.value后会触发两个get方法,因为this.name的this指向proxy,访问proxy的name属性又会触发get方法。
总结
proxy可以代理整个对象,相比于Object.defineProperty,对对象属性的增加,删除等操作都会被捕捉到,使用上也更加灵活,方便。