字面意思的理解就是代理。編程
用於定義基本操做的自定義行爲,就是咱們能夠自定義某些行爲,好比屬性的查找,賦值,枚舉,函數調用等。
實際上咱們利用這個Proxy實現對編程語言進行編程,就是把一些內部的方式,內置的方法改變了,這種編程就叫作語言編程。屬性代理就作攔截。
關於Proxy須要注意的地方有:Proxy內部的this關鍵字的指向是Proxy代理自己;它的構建方式須要藉助一個Proxy的構造函數new Proxy(target,handler),其中target叫作目標對象,Proxy構造函數返回的是一個包裝事後的目標對象,handler是代理的行爲的函數。數組
let handler = { get: function(target, name) { return name in target ? target[name] : 'Eric'; } }; let p = new Proxy({}, handler); p.name; // Eric let proxy = new Proxy({}, { get: function(target, property) { return 'Eric'; } }); let obj = Object.create(proxy); obj.name; // Eric (說明Proxy是能夠繼承的)
get
, 攔截某個屬性的讀取操做,接收三個參數:target(目標對象)、property(屬性名)、receiver(通常是Proxy對象自己,可選參數)app
let teacher = { name: "Eric" }; let proxy = new Proxy(teacher, { get: function(target, property) { if (property in target) { return target[property]; } else { throw new ReferenceError("\"" + property + "\" does not exist."); } } }); proxy.name; // Eric proxy.age; // ReferenceError: "age" does not exist.
get屬性攔截能夠繼承,須要注意的一點是,當某個對象不可配置(configurable)或者不可寫(writable),使用get會報錯。編程語言
set
, 攔截某個屬性的賦值操做
set屬性有四個參數:target(目標對象)、property(屬性名)、value(屬性值)、receiver(Proxy實例自己,可選參數)函數
let handler = { set: function(obj, prop, value) { //若是不是一個整數就拋出一個錯誤‘The value must an integer’ if (!Number.isInteger(value)) { throw new TypeError('The value must an integer'); } /* document.getElementById(prop).innerHTML = value */ obj[prop] = value; } }; let teacher = new Proxy({}, handler); teacher.name = 'Eric'; // TypeError: The value must an integer
一樣的,在不可配置(configurable),不可寫(writable)的裏面,使用set不生效。this
apply
, 函數調用、call和apply攔截
apply接收三個參數:target(目標對象)、thisArg(目標對象this)、argumentsList(目標對象參數數組)代理
var handler = { apply (target, ctx, args) { return Reflect.apply(...arguments); } }; let target = function () { return 'I am Eric'; }; let handler = { apply: function () { return 'I am Iven'; } }; let teacher = new Proxy(target, handler); teacher(); // I am Iven
has
, 攔截對象是否具備某個屬性 - hasProperty
has有兩個參數:target(目標對象)、prop(查詢的屬性名)。返回一個布爾值,true or false。code
let handler = { has (target, key) { if (key.startsWith('_')) { return false; } return key in target; } }; let target = { _property: 'private', property: 'public' }; let proxy = new Proxy(target, handler); '_property' in proxy; // false
注意的點:has不攔截for in循環;對象不可配置(configurable)時,使用has會報錯。orm
construct
, 攔截new操做符
construct接收三個參數:target(目標對象)、argumentsList(構造函數參數)、newTarget(最初被調用的構造函數,爲了方便可以獲得原來構造函數想要獲得的結構)。對象
var handler = { construct (target, args, newTarget) { return new target(...args); } }; var teacher = new Proxy( function () {}, { construct: function(target, args) { return { name: 'Eric' }; } } ); new teacher(); // { name: 'Eric' }
注意:返回值必須是對象。
ownKeys
, 攔截屬性遍歷
own只有一個參數:target(目標對象)。
let target = { Eric: 100, Iven: 200, }; let handler = { ownKeys(target) { return Reflect.ownKeys(target).filter(key => target[key] < 150); } }; let proxy = new Proxy(target, handler); Object.keys(proxy); // Eric
deleteProperty
, 攔截刪除操做
deleteProperty接收兩個參數:target(目標對象)、property(刪除的屬性名)。對象不可配置(configurable),使用deleteProperty會報錯
defineProperty
, 攔截Object.defineProperty
defineProperty接收三個參數:target(目標對象)、property(屬性名)、descriptor(描述樹)。屬性不可擴展(non-extensible)會報錯,不可配置(configurable)或者不可寫(writable)使用defineProperty不生效。
getOwnPropertyDescriptor
, 攔截Object.getOwnPropertyDescriptor
getOwnPropertyDescriptor接收兩個參數:target(目標對象)、prop(屬性名稱)。
getPrototypeOf
, 攔截獲取對象原型
getPrototypeOf 接收一個參數:target (目標對象)。必須返回對象或null。
isExtensible
, 攔截Object.isExtensible
getPrototypeOf 接收一個參數:target (目標對象)。必須返回布爾值。
preventExtensions
, 攔截Object.preventExtensions
preventExtensions 接收一個參數:target (目標對象)。必須返回一個布爾值。
setPrototypeOf
, 攔截Object.setPrototypeOf
setPrototypeOf 接收兩個參數:target (目標對象)、proto (原型對象)。
設置代理以後如何獲得默認的行爲?有兩種方式,一種是Proxy代理取消,另外一種是使用reflect。
內部提供的方法:revocable
let target = {}; let handler = {}; let { proxy, revoke } = Proxy.revocable(target, handler); revoke(); proxy.name; // ypeError: Cannot perform 'get' on a proxy that has been revoked