proxy

56 阅读1分钟

image.png

image.png

interface User {
    name: string,
    age: number
}

const person: User = {name: 'menffyzheng', age: 18}
// Proxy第一个参数,代理的目标只能是对象、数组、函数、set、map,其他类型会报错
const personProxy = new Proxy(person, {
    // 取值
    get(target: User, p: string | symbol, receiver: any): any {
        if (target.age <= 18) {
            return Reflect.get(target, p, receiver);
        } else {
            return 'menffyzheng成年了';
        }
    },
    // 赋值
    // set(target: User, p: string | symbol, value: any, receiver: any): boolean {
    //     return true;
    // },
    // // 拦截函数调用
    // apply(target: User, thisArg: any, argArray: any[]): any {
    // },
    // // 拦截in操作符
    // has(target: User, p: string | symbol): boolean {
    //     return true;
    // },
    // // 拦截 for in 方法
    // ownKeys(target: User): ArrayLike {
    // },
    // // 拦截new操作符
    // construct(target: User, argArray: any[], newTarget: Function): object {
    //     return {};
    // },
    // // 拦截删除操作
    // deleteProperty(target: User, p: string | symbol): boolean {
    //     return true;
    // }
})

console.log(personProxy.age)

对象取值方法除了可以

person.age

也可以Reflect.get(person, 'age', person)

Reflect里的receiver参数位置,也就是Reflect.get方法里的第三个参数,是为了保证上下文的正确而使用的,它其实就等于第一个参数。

// 观察者模式,类似vuex的状态变化监控,我觉得跟watch方法也很类似
const list: Set = new Set();
const autoRun = (cb: Function) => {
    if (!list.has(cb)) {
        list.add(cb);
    }
}
const observable = (params: T) => {
    return new Proxy(params, {
        set(target: T, p: string | symbol, value: any, receiver: any): boolean {
            const result = Reflect.set(target, p, value, receiver);
            list.forEach(fn => fn());
            return result;
        }
    })
}

const paramsProxy = observable({name: 'menffyzheng', attr: 'test'})
autoRun(() => {
    console.log('执行通知函数,有变化了!!')
})
console.log(paramsProxy.name);
paramsProxy.attr = 'test2'
paramsProxy.attr = 'test3'

image.png