《es6標準入門》知識整理(3) - Proxy

Proxy介紹

Proxy 用於修改某些操做的默認行爲;能夠理解成,在目標對象以前架設一層"攔截",外界對對象的訪問,都必須先經過這層攔截,所以提供了一層機制,能夠對外界的訪問進行過濾和改寫。javascript

const proxy = new Proxy(target,handler); target表示所要攔截的目標對象,handler參數也是一個對象,用來定製攔截行爲。
    const obj = new Proxy({}, {
                get: function(target, key, receiver) {
                    console.log(`getting ${key}`);
                    return Reflect.get(target, key, receiver);
                },
                set: function(target, key, value,receiver) {
                    console.log(`setting ${key}`)
                    return Reflect.set(target, key, value, receiver)
                }
            })
     obj.count = 1
     console.log(++obj.count)//2

proxy實例的常見方法

get(target,prop,receiver ):攔截某個屬性的讀取,三個參數依次爲目標對象、屬性名和 proxy 實例自己 receiver, 其中 receiver 爲可選;java

function createArray(...elements) {
                let handler = {
                    get(target, propKey, receiver) {
                        console.log(propKey)
                        let index = Number(propKey);
                        if(index < 0) {
                            propKey = String(target.length + index);
                        }
                        return Reflect.get(target, propKey, receiver)
                    }
                };
                let target = [];
                target.push(...elements);
                return  new Proxy(target, handler);
     }
    let arr = createArray('a','b','c');
    console.log(arr[-1]);// c
    console.log(arr[0]);// b
    console.log(arr[1])// a

這個例子用 get 攔截,實現根據數組索引讀取數組;當索引爲負時,表示數組遍歷爲從後到前;因此,當數組的位置是 -1 的時候,就會輸出數組的倒數第一個成員 c數組

set(target,prop, value, receiver):用來攔截某個屬性的賦值操做; prop 爲屬性名,value 爲屬性值,receiver 依舊可選;app

用set()做爲數據驗證:函數

let validator= {
                set: function(obj,prop,value) {
                    if(prop ==='age') {
                        if(!Number.isInteger(value)) {
                            throw new TypeError('The age is not an integer')
                        }
                        if(value > 200) {
                            throw new RangeError('The age seems invalid')
                        }
                    }
                    // 對於age之外的屬性,直接保存
                    obj[prop] = value;
                }
    }
    let person = new Proxy({}, validator)
    person.age = 100;
    console.log(person.age)// 100
    person.age = 300;
    console.log(person.age);// 報錯

任何不符合要求的age屬性賦值,都會報錯。this

apply(target,ctx, args):攔截函數的調用,call 和 apply 操做;參數 ctx 指的是目標對象的上下文對象 (this) 和目標對象的參數數組。代理

const twice = {
          apply(target, ctx, args) {
          console.log(args);// 1,2
          return Reflect.apply(...arguments)*2;
       }
    };
    function sum(left, right) {
        return left + right;
    };
    const proxy = new Proxy(sum,twice);
    console.log(proxy(1,2));//6

當執行proxy()時,會被apply()攔截;code

has(target,key):用來攔截 hasProperty 操做,即判斷對象是否具備某個屬性;典型的操做就是 in 運算符。對象

const handler = {
                has(target,key) {
                    if(key[0] === '_') {
                        return false;
                    }
                    return key in target;
                }
     };
    const target = {_prop: 'foo', prop: 'foo'};
    const proxy = new Proxy(target,handler);
    console.log('_prop' in proxy);// false;

這裏的代碼中,若是原對象的屬性名的第一個字符時下劃線,proxy.has() 就會返回 false,從而不被 in 運算符發現。注意:has() 攔截的是hasProperty 操做,而不是 hasOwnProperty 操做,即它不判斷屬性來源。索引

this問題

雖然 proxy 能夠代理針對目標對象的訪問,但它不是目標對象的透明代理。不作任何攔截的狀況下,也沒法保證與目標對象的行爲一致。主要緣由就是在Proxy 代理的狀況下,目標對象內部的 this 會指向 Proxy 代理。

const target = {
                m: function () {
                    console.log(this === proxy)
                }
            }
            const handler = {};
            const proxy = new Proxy(target,handler);
            target.m()// false
            proxy.m()// true

上面代碼中,一旦 proxy 代理 target.m,後者內部的 this 就指向了 proxy 而不是 target 了。

相關文章
相關標籤/搜索