TS高级-Proxy和Reflect
Proxy
ES6 新增的对象代理,相当于一个拦截器。
详情见 JS 代理(Proxy)一章。
基本使用
let person = { name: "张三", age: 18 };
person.name; // 取值操作
person.name = "李四"; // 赋值操作
let personProxy = new Proxy(person, {
// 创建一个拦截器 @1
// 拦截取值操作
get() {},
// 拦截赋值操作
set(target, key, value, receiver) {
// @2
return true;
},
// 拦截函数调用
apply() {},
// 拦截in操作符,
has() {},
// 拦截for in
ownKeys() {},
// 拦截new操作符
construct() {},
// 拦截delete操作符
deleteProperty() {},
});
@1:拦截器接收两个参数:
- target:需要被代理的对象(只接收引用数据类型:对象、数组、函数、set、map);
- handler:一个通常以函数作为属性的对象,处理器对象占位符,对处理对象的描述;
@2:set 接收四个参数:
- target:代理对象本身(此处为 person);
- key:操作的属性(此处为 name);
- value:操作的属性的值(此处为李四);
- receiver:也是代理对象本身,主要是为了内部嵌套多个函数时保证上下文的正确。
Reflect
反射。和 Proxy13 个代理方法是一样的。但是它可以直接操作对象。
get()
可以通过 Reflect.get()来获取一个对象的属性:
Reflect.get(target, key, receiver);
- target:需要被反射的对象(只接收引用数据类型:对象、数组、函数、set、map);
- key:需要获取值的属性;
- receiver:也是被反射的对象本身,主要是为了内部嵌套多个函数时保证上下文的正确。
例如:
let person = { name: "张三", age: 18 }; console.log(person.name); // 可以直接获取 console.log(Reflect.get(person, "name")); // 通过Reflect.get()获取
set()
可以通过 Reflect.set()来修改一个对象的属性:
Reflect.get(target, key, value, receiver);
- target:需要被反射的对象(只接收引用数据类型:对象、数组、函数、set、map);
- key:需要修改值的属性;
- value:修改的值;
- receiver:也是被反射的对象本身,主要是为了内部嵌套多个函数时保证上下文的正确。
console.log(Reflect.set(person, "name", "李四", person)); // true
console.log(person); // { name: "李四", age: 18 }
返回值:true/false
示例
let person = { name: "张三", age: 18 };
let personProxy = new Proxy(person, {
get(target, key, receiver) {
if (target.age <= 18) {
return Reflect.get(target, key, receiver);
} else {
return "已成年";
}
},
});
cnosole.log(personProxy.age); // 18
实现观察者模式
const list: Set<Function> = new Set();
const autoRun = (cb: Function) => {
if (!list.has(cb)) {
list.add(cb);
}
};
const observable = <T extends object>(params: T) => {
// Proxy代理对象只支持引用数据类型,所以需要限制传入的类型
return new Proxy(params, {
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
list.forEach((fn) => fn());
return result;
},
});
};
测试观察者模式:
// 设置一个可供观察的对象
const personProxy = observable({ name: "张三", attr: "摸鱼" });
autoRun(() => {
// 订阅函数
console.log("有变化了");
});
personProxy.name = "李四"; // 有变化了 @1
@1:在尝试修改的时候观察对象的值时,会调用订阅的函数。修改几次数据将会执行几次订阅函数