概述:es6
Proxy 用於修改某些操做的默認行爲,等同於在語言層面作出修改,因此屬於一種「元編程」(meta programming),即對編程語言進行編程。
編程
Proxy 能夠理解成,在目標對象以前架設一層「攔截」,外界對該對象的訪問,都必須先經過這層攔截,所以提供了一種機制,能夠對外界的訪問進行過濾和改寫。Proxy 這個詞的原意是代理,用在這裏表示由它來「代理」某些操做,能夠譯爲「代理器」。app
var 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); } });
上面代碼對一個空對象架設了一層攔截,重定義了屬性的讀取(get
)和設置(set
)行爲。這裏暫時先不解釋具體的語法,只看運行結果。對設置了攔截行爲的對象obj
,去讀寫它的屬性,就會獲得下面的結果。編程語言
obj.count = 1 // setting count! ++obj.count // getting count! // setting count! // 2
上面代碼說明,Proxy 實際上重載(overload)了點運算符,即用本身的定義覆蓋了語言的原始定義。函數
ES6 原生提供 Proxy 構造函數,用來生成 Proxy 實例。this
var proxy = new Proxy(target, handler);
Proxy 對象的全部用法,都是上面這種形式,不一樣的只是handler
參數的寫法。其中,new Proxy()
表示生成一個Proxy
實例,target
參數表示所要攔截的目標對象,handler
參數也是一個對象,用來定製攔截行爲。spa
下面是另外一個攔截讀取屬性行爲的例子。prototype
var proxy = new Proxy({}, { get: function(target, property) { return 35; } }); proxy.time // 35 proxy.name // 35 proxy.title // 35
上面代碼中,做爲構造函數,Proxy
接受兩個參數。第一個參數是所要代理的目標對象(上例是一個空對象),即若是沒有Proxy
的介入,操做原來要訪問的就是這個對象;第二個參數是一個配置對象,對於每個被代理的操做,須要提供一個對應的處理函數,該函數將攔截對應的操做。好比,上面代碼中,配置對象有一個get
方法,用來攔截對目標對象屬性的訪問請求。get
方法的兩個參數分別是目標對象和所要訪問的屬性。能夠看到,因爲攔截函數老是返回35
,因此訪問任何屬性都獲得35
。代理
注意,要使得Proxy
起做用,必須針對Proxy
實例(上例是proxy
對象)進行操做,而不是針對目標對象(上例是空對象)進行操做。code
若是handler
沒有設置任何攔截,那就等同於直接通向原對象。
var target = {}; var handler = {}; var proxy = new Proxy(target, handler); proxy.a = 'b'; target.a // "b"
上面代碼中,handler
是一個空對象,沒有任何攔截效果,訪問proxy
就等同於訪問target
。
一個技巧是將 Proxy 對象,設置到object.proxy
屬性,從而能夠在object
對象上調用。
var object = { proxy: new Proxy(target, handler) };
Proxy 實例也能夠做爲其餘對象的原型對象。
var proxy = new Proxy({}, { get: function(target, property) { return 35; } }); let obj = Object.create(proxy); obj.time // 35
上面代碼中,proxy
對象是obj
對象的原型,obj
對象自己並無time
屬性,因此根據原型鏈,會在proxy
對象上讀取該屬性,致使被攔截。
同一個攔截器函數,能夠設置攔截多個操做。
var handler = { get: function(target, name) { if (name === 'prototype') { return Object.prototype; } return 'Hello, ' + name; }, apply: function(target, thisBinding, args) { return args[0]; }, construct: function(target, args) { return {value: args[1]}; } }; var fproxy = new Proxy(function(x, y) { return x + y; }, handler); fproxy(1, 2) // 1 new fproxy(1,2) // {value: 2} fproxy.prototype === Object.prototype // true fproxy.foo // "Hello, foo"
轉自: ECMAScript 6 入門
做者:阮一峯