1. 程式人生 > >ES6代理器Proxy簡介

ES6代理器Proxy簡介

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.fooproxy['foo']
  • set(target, propKey, value, receiver):攔截物件屬性的設定,比如proxy.foo = vproxy['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