Es6入門之proxy

1. 概述

Proxy 用於修改某些操做的默認行爲,等同於在語言層面作出修改,因此屬於一種『元編程』即對編程語言進行編程。編程

1.1 理解

Proxy 是在目標對象以前架設一層『攔截』,外部對對象的訪問,都須要通過該層攔截。所以在攔截中對外界的訪問進行過濾和改寫。數組

在Es6 中 提供了原生的 Proxy 構造函數,能夠用來生成 Proxy實例。app

let proxy = new Proxy(target, handler)
複製代碼

Proxy 對象的全部用法,都是上面的形式,不一樣的只是handler參數的寫法。其中new Proxy() 表示生成一個 Proxy實例,target 參數表示全部攔截的目標對象, handler 參數也是一個對象,用來定製攔截行爲。以下:編程語言

let proxy = new Proxy({}, {
    get: function(target, property) {
        return 35
    }
})

proxy.time // 35
proxy.name // 35
proxy.title // 35
複製代碼

解讀:函數

在上面中,做爲構造函數,Proxy接受兩個參數。第一個參數即所要代理的目標對象,若是沒有 Proxy的介入,操做原來要訪問的就是這個對象。第二個參數是一個配置對象,用來對每一個代理對象的操做,提供具體的函數和攔截操做。上述代碼中有一個 get 函數,用來攔截對目標對象屬性的訪問請求。this

另外,要使 Proxy起做用,必須針對 Proxy 實例進行操做,而不是針對目標對象進行操做。spa

若是 handler 沒有設置任何攔截,那就等同於直接通向原對象。以下:代理

let target = {}
let handler = {}
let proxy = new Proxy(target, handler)


proxy.a = 'b'
target.a = 'b'
複製代碼

對於上面的例子,咱們能夠講Proxy對象,設置到 object.proxy屬性,從而能夠在object對象上調用。code

let object = {proxy: new Proxy(target, handler)}
複製代碼

Proxy 實例也能夠做爲其餘對象的原型對象。對象

let proxy = new Proxy({}, {
    get: function(target, property) {
        retrun 35
    }
})

let obj = Object.create(proxy)
obj.time    // 35

另外同一個攔截器,能夠設置多個攔截操做。
複製代碼

經常使用的Proxy支持的攔截操做以下:

  • get(target, propKey, receiver): 攔截對象屬性的讀取,好比 proxy.foo 和 proxy['foo']
  • set(target, propKey, value, receiver): 攔截對象屬性的設置,好比 proxy.foo = v 或 proxy['foo'] = v, 返回一個布爾值
  • has(target, proKey): 攔截propKey in proxy的操做,返回一個布爾值
  • apply(target, object, args): 攔截Proxy 實例做爲函數調用的操做,好比 proxy(...args)、proxy.call(object, ...args) 、 proxy.apply(...)。
  • deleteProperty(target, proKey): 攔截 delete proxy[propKey]的操做,返回一個布爾值
  • ownKeys(target): 攔截 Object.getOwnProPertyNames(proxy),返回一個數組。該方法返回目標對象全部自身的屬性的屬性名,而Object.keys() 的返回結果僅包括目標對象自身的可遍歷屬性。

1.2 get()

get 方法用於攔截某個屬性的讀取操做,能夠接受三個參數,依次爲目標對象、屬性名和proxy實例自己,最後一個參數可選。

let p = {
    name: '李四'
}

let proxy = new Proxy(p, {
    get: function(target, property) {
        if (property in target) {
            retrun target[property]
        } else {
            console.log('報錯')
        }
    }
})

proxy.name // '李四'
proxy.age  // '報錯'
複製代碼

注意點

  • get方法能夠繼承
  • get方法能夠進行鏈式操做

1.3 set

set 方法用來攔截某個屬性的賦值操做,能夠接受四個參數,依次爲目標對象、屬性名、屬性值和Proxy實例自己,最後一個可選

let v = {
    set: function(obj, prop, value) {
         if (prop === 'age') {
             if(!Number.isInteger(value)) {
                 console.log('報錯')
             }
             
             if(value > 200) {
                 console.log('成功')
             }
             
             obj[prop] = value
         }
    }
}

let p = new Proxy({}, v)

p.age = 100

p.age   // 100

p.age = 'n'
p.age   // 報錯
複製代碼

利用set方法,能夠數據綁定,即每當對象發生變化時,會自動更新Dom

若是目標對象自身的某個屬性,不可寫且不可配置,那麼Set 方法將不起做用。

1.4 apply()

apply 方法攔截函數的調用、call 和 apply操做。它能夠接受三個參數,分別時目標對象、目標對象的上下文對象(this)和目標對象的參數數組。

let h = {
    apply(target, ctx, args) {
        return Reflect.apply(...arguments)
    }
}

let target = function() {return 'haha')
let h = {
    apply: function() {
        return 'heihei'
    }
}

let p = new Proxy(taraget, h)

p() // 'heihei'
複製代碼

1.5 has

has 方法用來攔截 HasProperty 操做, 即判斷對象是否具備某個屬性時,這個方法會生效。

has 方法能夠接受兩個參數,分別時目標對象、須要查詢的屬性名。

注意:has 方法攔截的時 HasProperty操做,而不是HasOwnProperty操做,即has 方法不判斷一個屬性是對象自身的屬性,仍是繼承的屬性。

1.6 construct

construct 方法用於攔截 new命令,下面是攔截對象的寫法

let h = {
    construct(target, args, newTarget) {
        retrun new target(...args)
    }
}

target: 目標對象
args: 構造函數的參數對象
newTarget: 創造實例對象時,new命令做用的構造函數
複製代碼

1.7 deleteProperty()

deleteProperty 方法用於攔截 delete 操做,若是這個方法拋出錯誤或者返回false,當前屬性就沒法被delete命令刪除。

2. this問題

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

相關文章
相關標籤/搜索