ES6代理器Proxy簡介
阿新 • • 發佈:2018-12-20
Proxy概述
Proxy 用於修改某些操作的預設行為,等同於在語言層面做出修改,所以屬於一種“超程式設計”(meta programming),即對程式語言進行程式設計。
Proxy 可以理解成,在目標物件之前架設一層“攔截”,外界對該物件的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。Proxy 這個詞的原意是代理,用在這裡表示由它來“代理”某些操作,可以譯為“代理器”。
Proxy用法
const proxy = new Proxy(target, handler); // new Proxy()
表示生成一個Proxy
例項,target
引數表示所要攔截的目標物件,handler
Proxy支援的攔截操作
引數說明:target指目標物件, propKey指屬性名稱,receiver指Proxy例項
- get(target, propKey, receiver):攔截物件屬性的讀取,比如
proxy.foo
和proxy['foo']
。 - set(target, propKey, value, receiver):攔截物件屬性的設定,比如
proxy.foo = v
或proxy['foo'] = v
,返回一個布林值。 - has(target, propKey):攔截
propKey in proxy
的操作,返回一個布林值。 - deleteProperty(target, propKey)
delete proxy[propKey]
的操作,返回一個布林值。 - ownKeys(target):攔截
Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
迴圈,返回一個數組。該方法返回目標物件所有自身的屬性的屬性名,而Object.keys()
的返回結果僅包括目標物件自身的可遍歷屬性。 - getOwnPropertyDescriptor(target, propKey):攔截
Object.getOwnPropertyDescriptor(proxy, propKey)
- defineProperty(target, propKey, propDesc):攔截
Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一個布林值。 - preventExtensions(target):攔截
Object.preventExtensions(proxy)
,返回一個布林值。 - getPrototypeOf(target):攔截
Object.getPrototypeOf(proxy)
,返回一個物件。 - isExtensible(target):攔截
Object.isExtensible(proxy)
,返回一個布林值。 - setPrototypeOf(target, proto):攔截
Object.setPrototypeOf(proxy, proto)
,返回一個布林值。如果目標物件是函式,那麼還有兩種額外操作可以攔截。 - apply(target, object, args):攔截 Proxy 例項作為函式呼叫的操作,比如
proxy(...args)
、proxy.call(object, ...args)
、proxy.apply(...)
。 - construct(target, args):攔截 Proxy 例項作為建構函式呼叫的操作,比如
new proxy(...args)
。
Proxy.revocable()
Proxy.revocable
方法返回一個可取消的 Proxy 例項。
let target = {};
let handler = {};
let {proxy, revoke} = Proxy.revocable(target, handler);
proxy.foo = 123;
proxy.foo // 123
revoke();
proxy.foo // TypeError: Revoked
Proxy.revocable
方法返回一個物件,該物件的proxy
屬性是Proxy
例項,revoke
屬性是一個函式,可以取消Proxy
例項。上面程式碼中,當執行revoke
函式之後,再訪問Proxy
例項,就會丟擲一個錯誤。
Proxy.revocable
的一個使用場景是,目標物件不允許直接訪問,必須通過代理訪問,一旦訪問結束,就收回代理權,不允許再次訪問。
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