TS 进阶用法 proxy & Reflect
Proxy
对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)
- target
要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
- handler
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
handler.get() 本次使用的 get
属性读取操作的捕捉器。
handler.set() 本次使用的 set
属性设置操作的捕捉器。
Reflect
与大多数全局对象不同 Reflect 并非一个构造函数,所以不能通过 new 运算符对其进行调用,或者将 Reflect 对象作为一个函数来调用。Reflect 的所有属性和方法都是静态的(就像 Math 对象)
- Reflect.get(target, name, receiver)
Reflect.get 方法查找并返回 target 对象的 name 属性,如果没有该属性返回 undefined
- Reflect.set(target, name,value, receiver)
Reflect.set 方法设置 target 对象的 name 属性等于 value。
type Person = {
name: string
age: number
text: string
}
const proxy = (object: any, key: any) => {
return new Proxy(object, {
get(target, prop, receiver) {
console.log(`get key======>${key}`)
return Reflect.get(target, prop, receiver)
},
set(target, prop, value, receiver) {
console.log(`set key======>${key}`)
return Reflect.set(target, prop, value, receiver)
},
})
}
const logAccess = (object: Person, key: 'name' | 'age' | 'text') => {
return proxy(object, key)
}
let man: Person = logAccess(
{
name: 'mk',
age: 20,
text: '我',
},
'age'
)
man.age = 30
console.log(man)
使用泛型+keyof 优化
type Person = {
name: string
age: number
text: string
}
const proxy = (object: any, key: any) => {
return new Proxy(object, {
get(target, prop, receiver) {
console.log(`get key======>${key}`)
return Reflect.get(target, prop, receiver)
},
set(target, prop, value, receiver) {
console.log(`set key======>${key}`)
return Reflect.set(target, prop, value, receiver)
},
})
}
const logAccess = <T>(object: T, key: keyof T): T => {
return proxy(object, key)
}
let man: Person = logAccess(
{
name: 'mk',
age: 20,
text: '我',
},
'age'
)
let man2 = logAccess(
{
id: 1,
name: 'mk2',
},
'name'
)
man.age = 30
console.log(man)
案例简单实现一个mobx观察者模式
const list: Set<Function> = new Set()
const autoRun = (cb: Function) => {
if (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())
console.log(list)
return result
}
})
}
const person = observable({ name: "mk", attr: "威猛先生" })
autoRun(()=>{
console.log('我变化了')
})
person.attr = '威猛个捶捶'