Proxy
(代理)对象用于自定义JavaScript基本操作的形为(如:属性查找、赋值、枚举、函数调用等),该对象是JavaScript语言标准ES 6
(ECMAScript 2015
)中新增的对象,通过该对象使我们具有了对JavaScript语言层面进行修改的能力。
1. Proxy
语法说明
var p = new Proxy(target, handler);
参数
target
-被代理的一个目标对象(可以是任何类型的对象、数组、函数,甚至是另一个代理)handler
-处理对象,其属性是定义代理时的行为函数,在目标对象上执行的代理操作都会被些函数处理返回值
-代理对象实例
Proxy
即“代理”,我们通过new Proxy()
构造函数,来对target
设置处理对象handler
。初始化后会返回一个代理实例对象p
,该对象是target
的代理器,访问target
对象的形为都会首先经过该代理器处理。代理器会判断这种形为有没有在handler
中定义,如果已定义则由代理形为处理,如果未定义则由target
处理。
2. Proxy.revocable()
方法
2.1 revocable()
语法
Proxy.revocable(target, handler);
创建一个可撤销的Proxy
对象。
可撤销的Proxy
对象允有{proxy: proxy, revoke: revoke}
两个属性:
proxy
-通过调用new Proxy(target, handler)
创建的代理对象handler
-一个没有参数的函数,用于撤销proxy
revoke()
方法调用后,代理会变为无效状态,handler
上的任何trap
都会返回TypeError
。该方法不可重复调用。
2.2 revocable()
方法的使用
var revocable = Proxy.revocable({}, { get: function(target, name) { return "[[" + name + "]]"; } }); var proxy = revocable.proxy; console.log(proxy.foo); // "[[foo]]" // 撤销代理 revocable.revoke(); console.log(proxy.foo); // 抛出 TypeError proxy.foo = 1 // 再次抛出 TypeError delete proxy.foo; // 仍然是 TypeError typeof proxy // "object"
3. handler
对象方法
handler
是一个包含陷入(trap)代理的占位符函数。
所有陷入指令都是可选的,如果陷入指令未定义那么会继续定向到target
对象来处理。所有陷入指令如下:
handler.getPrototypeOf()
-Object.getPrototypeOf
的陷入指令(代理)handler.setPrototypeOf()
-Object.setPrototypeOf
的陷入指令(代理)handler.isExtensible()
-Object.isExtensible
的陷入指令(代理)handler.preventExtensions()
-Object.preventExtensions
的陷入指令(代理)handler.getOwnPropertyDescriptor()
-Object.getOwnPropertyDescriptor
的陷入指令(代理)handler.defineProperty()
-Object.defineProperty
的陷入指令(代理)handler.has()
-in
操作符的陷入指令(代理)handler.get()
-Object.get
的陷入指令(代理)handler.set()
-Object.set
的陷入指令(代理)handler.deleteProperty()
-delete
操作符的陷入指令(代理)handler.ownKeys()
-Object.getOwnPropertyNames
的陷入指令(代理)handler.apply()
-function
调用的陷入指令(代理)handler.construct()
-new
操作符(构造函数)的陷入指令(代理)
4. 使用示例
自定义访问器
定义get
代理,当用户访问属性不存在时返回'不存在'
:
var handler = { get: function(target, name){ return name in target? target[name] : '不存在'; } }; var p = new Proxy({}, handler); p.a = 1; p.b = undefined; console.log(p.a, p.b); // 1, undefined console.log('c' in p, p.c); // false, '不存在'
当不定义具体代理形为时,形为会继续交由对象本身处理:
var target = {}; var p = new Proxy(target, {}); p.a = 37; // 由对象本身的set处理operation forwarded to the target console.log(target.a); // 37. 由对象本身的get处理
扩展构造函数
一个函数代理可以很容易地用一个新的构造函数扩展构造函数。扩展构造函数时,需要construct
和apply
两个处理器:
function extend(sup,base) { var descriptor = Object.getOwnPropertyDescriptor( base.prototype,"constructor" ); base.prototype = Object.create(sup.prototype); var handler = { construct: function(target, args) { var obj = Object.create(base.prototype); this.apply(target,obj,args); return obj; }, apply: function(target, that, args) { sup.apply(that,args); base.apply(that,args); } }; var proxy = new Proxy(base,handler); descriptor.value = proxy; Object.defineProperty(base.prototype, "constructor", descriptor); return proxy; } var Person = function(name){ this.name = name; }; var Boy = extend(Person, function(name, age) { this.age = age; }); Boy.prototype.sex = "M"; var Peter = new Boy("Peter", 13); console.log(Peter.sex); // "M" console.log(Peter.name); // "Peter" console.log(Peter.age); // 13