在 TypeScript (TS) 中,Proxy 和 Reflect 是两个与元编程(metaprogramming)和对象操作相关的核心特性。
它们一起提供了对象操作和拦截功能,便于捕获和修改对象的行为。
proxy
(代理) 和 Reflect
(反射) 参数一样。
基本用法
Proxy
Proxy
是一个内置的构造函数,用于创建代理对象。代理对象允许你定义一个叫做"陷阱"(trap)的函数,这些陷阱会拦截对目标对象的操作。这些操作包括读取属性、写入属性、调用方法等等。通过使用代理,你可以在对象的行为上插入自定义逻辑或拦截这些操作。
let person = { name: 'xx', age: 20 }
// proxy 支持对象,数组,函数,set,map
// 代理对象的常用模式:前面一个对象,后面一个对象用于描述前面的对象
person.name // 取值
person.name = 'xxx' // 赋值
let personProxy = new Proxy(person, {
// 拦截取值
get(person, prop) {
console.log(`getting ${prop} property`)
return person[prop]
},
// 拦截赋值 person name xxx
set(target, key, value, receiver) {
return true
},
// 拦截函数调用
apply() {
},
// 拦截 in 操作符
has () {
},
// 拦截 for in
ownKeys() {
},
// 拦截 new 操作符
construct() {
},
// 拦截删除的操作
deleteProperty(target, p) {
}
})
console.log(person.name) // 输出:“getting name property”,然后输出 “xxx”
Reflect
Reflect
是一个内置的对象,它提供了一组静态方法,用于执行一些与对象相关的默认操作。这些方法与代理对象一起使用,通常在陷阱中调用,以便在执行默认操作的同时添加自定义逻辑。
以下是一些常见的 Reflect
方法和它们的用法:
Reflect.get(target, propertyKey, receiver)
: 用于获取目标对象的属性值。Reflect.set(target, propertyKey, value, receiver)
: 用于设置目标对象的属性值。Reflect.has(target, propertyKey)
: 检查目标对象是否具有指定属性。Reflect.deleteProperty(target, propertyKey)
: 用于删除目标对象的属性。Reflect.construct(target, argumentsList, newTarget)
: 用于创建一个新的对象实例。Reflect.apply(target, thisArg, argumentsList)
: 用于调用目标对象的方法。
let person = { name: 'xx', age: 20 }
const target = { name: 'John' };
// 输出 age 的值
// console.log(Reflect.get(person, 'age', person));
// 修改 age 的值,返回 true
// console.log(Reflect.set(person, 'age', 23, person));
let personProxy = new Proxy(person, {
get(target, key, receiver) {
if (target.age < 18) {
return Reflect.get(target, key, receiver)
} else {
return "xx 成年了"
}
}
})
const proxy = new Proxy(target, {
get(target, prop) {
console.log(`Getting ${prop} property`);
return Reflect.get(target, prop);
},
set(target, prop, value) {
console.log(`Setting ${prop} property to ${value}`);
return Reflect.set(target, prop, value);
}
});
// age:17 输出:17 age:20 输出:xx 成年了
console.log(personProxy.age);
proxy.name = 'Alice'; // 输出: "Setting name property to Alice"
console.log(proxy.name); // 输出: "Getting name property",然后输出 "Alice"
实现观察者模式(简易版)
// 存储回调函数(观察者)的集合
const list: Set<Function> = new Set()
const autorun = (cb: Function) => {
if (!list.has(cb)) {
list.add(cb)
}
}
const observable = <T extends object>(params: T) => {
return new Proxy(params, {
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver)
list.forEach(fn => fn())
return result
}
})
}
// personProxy 对象被创建,开始时 list 为空。
const personProxy = observable({ name: 'xx', attr: "newbee" })
autorun(() => {
console.log("有变换了");
})
// 输出两遍 有变化了
// 修改 personProxy.attr 属性,触发 Proxy 的 set 方法,该方法会遍历 list 集合并调用已注册的回调函数,输出 "有变化了"
personProxy.attr = "no-newbee"
personProxy.name = 'xxx'