JS高级应用-Proxy代理

121 阅读2分钟

前言

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