前言
Proxy可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不是直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作的时候,可以添加一些需要的额外操作。在Vue3.x 时代,数据响应式主要是使用 Proxy()来实现的。
Proxy-基本用法
一个proxy对象由两部分组成:target、handler。target为被处理的目标对象,handler为声明处理target指定行为的对象。
let target = {
name: 'tom',
age: 27
}
let handler = {
get: function (target, key) {
console.log('getting ' + key);
return target[key]; // 不是target.key
},
set: function (target, key, value) {
console.log('setting ' + key);
target[key] = value;
}
}
let proxy = new Proxy(target, handler)
proxy.name //执行的是get的方法
// getting name
proxy.age = 30 //执行的是set的方法
//setting age
target&handler
// target 可以为空对象
let targetEpt = {}
let proxyEpt = new Proxy(targetEpt, handler)
// 调用 get 方法,此时目标对象为空,没有 name 属性
proxyEpt.name
// getting name
// 调用 set 方法,向目标对象中添加了 name 属性
proxyEpt.name = 'Tom'
// setting name
// "Tom"
// 再次调用 get ,此时已经存在 name 属性
proxyEpt.name
console.log(proxyEpt.name)
// getting name
// "Tom"
// 通过构造函数新建实例时其实是对目标对象进行了浅拷贝,因此目标对象与代理对象会互相 影响
targetEpt // {name: "Tom"}
// handler 对象也可以为空,相当于不设置拦截操作,直接访问目标对象
let targetEmpty = {}
let proxyEmpty = new Proxy(targetEmpty, {})
proxyEmpty.name = "Tom"
targetEmpty // {name: "Tom"}
实例方法
get()的方法实现继承
let proxy2 = new Proxy({}, {
get(target, propKey, receiver) {
// 实现私有属性读取保护
if(propKey[0] === 'a'){
console.log('error')
return
}
// console.log(propKey[0])
// console.log(propKey)
console.log('Getting' + propKey);
return target[propKey];
}
});
console.log(proxy2)
let obj = Object.create(proxy2);
console.log(obj)
obj.name
// Getting name
对于拦截target对象上的propKey的赋值操作,如果目标对象自身的某个属性,不可写且不可配置,那么set方法将不起作用。
let validator = {
set: function (obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// 对于满足条件的 age 属性以及其他属性,直接保存
obj[prop] = value;
}
};
let proxy = new Proxy({}, validator)
proxy.age = 100;
proxy.age // 100
proxy.age = 'oppps' // 报错
proxy.age = 300 // 报错
Reflect
ES6中将object中的一些明显属于语言的内部方法移植到Reflect对象上(当前的某些方法会同时的存在与Project和Reflect上),后面更新的方法部署在Reflect上。Reflect对象使用函数的方式实现了Object的命令式操作。
静态方法
Reflect.get(target, name, receiver)
查找并返回taget对象的name
let exam = {
name: "Tom",
age: 24,
get info(){
return this.name + this.age;
}
}
Reflect.get(exam, 'name'); // "Tom"
// 当 target 对象中存在 name 属性的 getter 方法, getter 方法的 this 会绑定 // receiver
let receiver = {
name: "Jerry",
age: 20
}
Reflect.get(exam, 'info', receiver); // Jerry20
// 当 name 为不存在于 target 对象的属性时,返回 undefined
Reflect.get(exam, 'birth'); // undefined
// 当 target 不是对象时,会报错
Reflect.get(1, 'name'); // TypeError