Proxy 在ES6 中引入,用于创建一个对象的代理。本文介绍了JavaScript中的Proxy对象,如何通过handler函数实现对象属性的拦截和自定义操作,以及get,set,delete Property等方法的用法和注意事项。还探讨了Proxy在拦截外部访问、数据类型验证、私有属性保护和观察者模式中的应用。
var proxy = new Proxy(target, handler)
关于handler 可拦截属性共有14种(方法13个),如下:
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() :属性读取操作的捕捉器。
handler.set() :属性设置操作的捕捉器。
handler.deleteProperty() :delete 操作符的捕捉器。
handler.ownKeys() :Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器。
handler.apply() :函数调用操作的捕捉器。
handler.construct() :new 操作符的捕捉器。
getPrototypeOf(target): 拦截Object.getPrototypeOf(proxy),返回一个对象
setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值
isExtensible(target): 拦截Object.isExtensible(proxy),返回一个布尔值
get(target,propKey,receiver):拦截对象属性的读取
set(target,propKey,value,receiver):拦截对象属性的设置
has(target,propKey):拦截propKey in proxy的操作,返回一个布尔值
deleteProperty(target,propKey):拦截delete proxy[propKey]的操作,返回一个布尔值
ownKeys(target):拦截Object.keys(proxy)、for...in等循环,返回一个数组
getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象
defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc),返回一个布尔值
preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值
apply(target, object, args):拦截 Proxy 实例作为函数调用的操作
construct(target, args):拦截 Proxy 实例作为构造函数调用的操作
【Reflect】
若需要在Proxy内部调用对象的默认行为,建议使用Reflect,其是ES6中操作对象而提供的新 API
基本特点:
只要Proxy对象具有的代理方法,Reflect对象全部具有,以静态方法的形式存在
修改某些Object方法的返回结果,让其变得更合理(定义不存在属性行为的时候不报错而是返回false)
让Object操作都变成函数行为
=== 可撤销的代理对象 ===
Proxy.revocable() 方法可以用来创建一个可撤销的代理对象。
// revocable 其结构为: {"proxy": proxy, "revoke": revoke},其中:
var revocable = Proxy.revocable(
{},
{
get(target, name) {
return "[[" + name + "]]";
},
},
);
var proxy = revocable.proxy;
proxy.foo; // "[[foo]]"
revocable.revoke();
console.log(proxy.foo); // 抛出 TypeError
proxy.foo = 1; // 还是 TypeError
delete proxy.foo; // 又是 TypeError
typeof proxy; // "object",因为 typeof 不属于可代理操作
=== 延伸阅读 14种可代理对象具体含义 ===
1、Object.getPrototypeOf(obj) : 指定对象的原型。
静态方法返回指定对象的原型(即内部 [[Prototype]] 属性的值)。
参数:obj 要返回其原型的对象。
2、Object.setPrototypeOf(obj, prototype) : 无返回值。
参数:obj 要设置其原型的对象; prototype 该对象的新原型(一个对象或 null)。
静态方法可以将一个指定对象的原型(即内部的 [[Prototype]] 属性)设置为另一个对象或者 null。
注意:应该避免设置对象的 [[Prototype]] 属性。而是使用 Object.create() 创建一个具有所需 [[Prototype]] 属性的新对象。
3、Object.isExtensible(obj) : 布尔值
Object.isExtensible() 静态方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
参数:obj 要设置其原型的对象;
默认情况下,对象是可扩展的:可以向它们添加新属性,并且它们的 [[Prototype]] 可以被重新赋值。
如果传入的参数不是一个对象,那么它将返回 false 而不会报错,因为按照定义,原始类型是不可变的。