1. 程式人生 > >ES6——Proxy(代理)、Reflect(反射)

ES6——Proxy(代理)、Reflect(反射)

Proxy(代理)

Proxy可以理解成,在目標物件之前架設一層“攔截”,外界對該物件的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫

Proxy這個詞的原意是代理,用在這裡表示由它來“代理”某些操作,可以譯為“代理器”。

語法

new Proxy(被代理物件,處理函式)

常用方法

           get(被代理物件,key)   代理物件屬性讀取

    set(被代理物件,key,value)   代理物件屬性設定

           has(被代理物件,key)   攔截key in object操作

deleteProperty(被代理物件,key)   攔截刪除操作

          ownKeys(被代理物件)    攔截Object.keys
                                   Object.getOwnPropertySymbols 
                                   Object.getOwnPropertyNames

例項

//供應商
let obj = {
    time: '2017-08-31',
    name: 'Tim',
    _r: 123
};

//代理商
let monitor = new Proxy(obj,{
        //代理讀取物件屬性
        get(target,key){
            //當讀取物件屬性時,將所有2017替換成2018
            return target[key].replace('2017','2018')
        },

        //代理設定物件屬性
        set(target,key,value
){ //只有key值是name的時候,才允許修改;否則返回原來的值。 if(key==='name'){ return target[key]=value; } else{ return target[key]; } }, //攔截key in object操作 has(target,key){ //只有key值是name的時候,才返回true;否則返回false。
if(key==='name'){ return target[key]; } else{ return false; } }, //攔截刪除操作 deleteProperty(target,key){ //只有key值以“_”開頭,才允許刪除。 if(key.indexOf('_') = 0){ delete target[key]; return true; } else{ return target[key] } }, //攔截Object.keys, Object.getOwnPropertySymbols, Object.getOwnPropertyNames ownKeys(target){ //使用陣列的filter方法過濾掉time屬性,不暴露出來 return Object.keys(target).filter(item=>item!='time') } } //讀取 console.log('讀取操作',monitor.time); //2018-08-31 //設定 monitor.time = '2019'; //設定失敗 monitor.name = 'Chen'; //設定成功 console.log('設定操作',monitor.time,monitor.name); //2018-08-31 Tim //has in object操作 console.log('has','name' in monitor); // true console.log('has','time' in monitor); // false //刪除操作 delete monitor.time; //並沒有成功 console.log('刪除操作', monitor); //time: '2017-08-31', name: 'Tim', _r: 123 //遍歷屬性操作 console.log(Object.keys(monitor)); // name, _r

Reflect(反射)

將Object物件的一些明顯屬於語言內部的方法(比如Object.defineProperty),放到Reflect物件上。

修改某些Object方法的返回結果,讓其變得更合理。

讓Object操作都變成函式行為。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)讓它們變成了函式行為。

常用方法

           get(被代理物件,key)   讀取物件屬性

    set(被代理物件,key,value)   設定物件屬性

           has(被代理物件,key)   相當於key in object

deleteProperty(被代理物件,key)   刪除

注意,Reflect.set會觸發Proxy.defineProperty攔截

例項

 let obj = {
        time: '2017-08-31',
        name: 'Tim',
        _r: 123
};

//get讀取操作
console.log('Reflect get讀取',Reflect.get(obj,'time'));

//set設定操作
Reflect.set(obj,'name','CCC');
console.log(obj);  // time: '2017-08-31', name: 'CCC', _r: 123

//has操作,相當於以前的key in obj 
console.log('Reflect has',Reflect.has(obj,'name');  // true

//刪除
const myObj = { foo: 'bar' };
Reflect.deleteProperty(myObj, 'foo');

Proxy和Reflect配合使用

{
    //資料校驗主程式
    function validator(target,validator){        
        return new Proxy(target,{
            _validator: validator,

            set(target,key,value,proxy){
                //判斷當前物件是否有這個key值
                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
        }
    }

    //類
    class Person{
        constructor(name,age){
            this.name = name;
            this.age = age;
            return validator(this,personValidators)
        }
    }

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

    console.log(person);  // {name: 'xiaoming' , age: 30}

    person.name=38; // 設定失敗,因為name需要是一個字串
    person.age=38;  // 設定成功
}