ES6 Proxy/Reflect 淺析

ES6 Proxy/Reflect

Proxy 攔截器

proxy是es6的新特性,簡單來說,便是對目標對象的屬性讀取、設置,亦或函數調用等操做進行攔截(處理)。es6

let proxy = new Proxy(target,handle)

target

一個proxy代理對象由兩部分組成target/handle。其中target爲目標對象,能夠爲一個空對象即(target={}),也能夠是一個含有屬性和方法的對象(target={foo:1,bar:2}),在進行let proxy=new Proxy(target,handle)的操做後,新的proxy對象會對target進行「淺拷貝」,即proxy、target兩個對象會相互影響。即:瀏覽器

let target = { _prop: 'foo', prop: 'foo' };
let proxy = new Proxy(target, handler);
proxy._prop = 'bar';
target._attr = 'new'
console.log(target._prop) // 'bar'
console.log(proxy._attr) //'new'

ES5 getter/setter

handle是實際運行的處理方法,Proxy的handle一共有13種方法,以最簡單經常使用的get/set方法爲例。在ES5中,對象就有get/set的訪問器(低版本瀏覽器不支持),它們的做用是在對象進行屬性的讀寫時,進行額外的操做。例如person對象下的age屬性,當它不在0-100之間時,給這個age的值重置爲0。app

var person = {
                get age(){
                    console.log('getter')
                    return this._age;//這裏千萬不能return this.age,會出錯
                },
                set age(val) {
                    console.log('setter')
                    this._age = val < 100 && val > 0 ? val:0
                   
                }
            };
    person.age = 10 //10
    person.age = 101 //0
    person.age = 'age' //0

在進行賦值操做時,會先觸發set、後觸發get,進行如person.age++的操做時,set、get的觸發順序爲:get=>set。以上就是ES5的getter/setter訪問器。函數

handle

在 Proxy中的handle中get、set方法也相似。即this

let handler = {
                get (target, key){
                    return target[key]
                },
                set (target, key, value) {
                    if (key === 'age') {
                        target[key] = value > 0 && value < 100 ? value : 0
                    }
                    return true;//必須有返回值
                }
            };

            let target = {};
            let proxy = new Proxy(target, handler);
            proxy.age = 22 //22

其中get可接受三個參數(target,key, receiver),target爲目標對象,key爲屬性名,receiver爲實際接受的對象,默認爲本例中新建的proxy,若是單獨指出一個對象,可以使指出對象受到相同的方法做用。例如:代理

let _proxy={};
   let handler = {
                get (target, key , receiver){
                    receiver=_proxy;
                    target[key]='test';
                    return Reflect.get(target,key,receiver);
                },
                set (target, key, value) {
                    if (key === 'age') {
                        target[key] = value > 0 && value < 100 ? value : 0
                    }
                    return true;//必須有返回值
                }
            };

            let target = {};
            let proxy = new Proxy(target, handler);
            proxy.age
            console.log(_proxy.age) // test

set方法 多一個value參數,爲屬性值,即 proxy.age=1,中的1。code

與ES5 setter/getter訪問器的區別是,在proxy中,proxy.age=1,只會執行 set的方法,而不是像ES5中的setter,會先執行set,後執行get。且proxy中的set必須有返回值,ES5的setter不用,這也正是由於在他以後還會執行getter,因此不須要。對象

Reflect 反射

Reflect與ES5的Object有點相似,包含了對象語言內部的方法,Reflect也有13種方法,與proxy中的方法一一對應。Proxy至關於去修改設置對象的屬性行爲,而Reflect則是獲取對象的這些行爲。
仍是剛纔的例子:ci

let _proxy = {}
 let handler = {
                get (target, key,recive){
                    return Reflect.get(target,key,recive)
                },
                set (target, key, value) {
                    if (key === 'age') {
                        target[key] = value > 0 && value < 100 ? value : 0
                    }
                    return Reflect.set(target,key,value,_proxy);
                }
            };

  let target = {};
  let proxy = new Proxy(target, handler);
  proxy.age = 33
  console.log(_proxy.age)//33

Reflect 也可與ES5的setter/getter配合使用,例如:get

var myObject = {
  foo: 1,
  bar: 2,
  get baz() {
    return this.foo + this.bar;
  },};

var myReceiverObject = {
  foo: 4,
  bar: 4,};

Reflect.get(myObject, 'baz', myReceiverObject) // 8

其他方法與Proxy均相同,區別便是,設置和獲取的關係。

Proxy和Reflect還有不少方法,好比apply做爲操做對象函數時觸發的方法,好比myObject =function(){return "it's Fn"}, myObject();會觸發handle中的apply方法。還有觸發has方法的_attr in obj等等共計13種方法,本次只以最簡單的set、get方法來舉例。

相關文章
相關標籤/搜索