ES6(Proxy和Reflect)

2019-03-29  本文已影响0人  陈裔松的技术博客

Proxy

代理,用于连接用户与真实的对象。通过代理,可以根据不同的业务逻辑,做相应的处理。

// 目标对象
let obj = {
    time: '2017-03-11',
    name: 'net',
    _r: 123
}

// 新建一个代理,代理对象:obj
let monitor = new Proxy(obj, {
    // 拦截对目标对象属性的读取
    // target:目标对象(obj),key:想要读取的属性
    get(target, key) {
        return target[key].replace('2017', '2018');
    },
    // 拦截对目标对象属性的设置
    // target:目标对象(obj),key:想要设置的属性,value:想要设置的值
    set(target, key, value) {
        // 自定义限制:只允许修改name属性
        if (key === 'name') {
            return target[key] = value;
        } else {
            return target[key];
        }
    },
    // 拦截key in object操作
    has(target, key) {
        // 自定义限制:只暴露name属性
        if (key === 'name') {
            return target[key];
        } else {
            return false;
        }
    },
    // 拦截对目标对象属性的删除
    deleteProperty(target, key) {
        // 自定义限制:只允许删除_开头的属性
        if (key.indexOf('_') > -1) {
            delete target[key];
            return true;
        } else {
            return target[key];
        }
    },
    // 拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames
    ownKeys(target){
        return Object.keys(target).filter(item => item != 'time');
    }
});

console.log(monitor.time);      // 2018-03-11   2017已经被替换成2018

monitor.time = '2018';
console.log(monitor.time);      // 2018-03-11   修改time属性失败

monitor.name = 'song';
console.log(monitor.name);      // song         修改name属性成功

console.log('name' in monitor); // true         暴露
console.log('time' in monitor); // false        未暴露

delete monitor.time;
console.log(monitor);           // Proxy {time: "2017-03-11", name: "song", _r: 123}
delete monitor._r;
console.log(monitor);           // Proxy {time: "2017-03-11", name: "song"}

console.log(Object.keys(monitor));  // ["name"]

Reflect

映射,用于映射真实的对象。其拥有的方法与Proxy的方法完全一致。

let obj = {
    time: '2017-03-11',
    name: 'net',
    _r: 123
}

console.log(Reflect.get(obj, 'name'));  // net
Reflect.set(obj, 'name', 'song');
console.log(Reflect.get(obj, 'name'));  // song
console.log(Reflect.has(obj, 'name'));  // true

使用场景(数据校验)

// 与传统校验方式相比,这种方式把校验规则单独抽离出来,减少与业务逻辑的耦合

// 通用代理生成函数
function validator(target, validator) {
    return new Proxy(target, {
        _validator: validator,
        set(target, key, value, proxy) {
            if (target.hasOwnProperty(key)) {
                let va = this._validator[key];
                if (!!va(value)) {
                    return Reflect.set(target, key, value, proxy);
                } else {
                    throw Error(`不能设置${key}到${value}`);
                }
            } else {
                throw Error(`${key}不存在`);
            }
        }
    })
}

// 校验规则
const personValidators = {
    name(val) {
        return typeof val === 'string';
    },
    age(val) {
        return typeof val === 'number' && val > 18;
    }
}

// 类Person实例化之后,得到的是一个对Person实例对象的代理
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
        return validator(this, personValidators); // this指向的是类的实例
    }
}

const person = new Person('lilei', 30);

console.log(person);    // Proxy {name: "lilei", age: 30}

person.name = 48;       // Uncaught Error: 不能设置name到48
上一篇 下一篇

猜你喜欢

热点阅读