Proxy
构造函数
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
语法:new Proxy(target, handler)
参数:
- target:要使用
Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理) - handler:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理
p的行为
方法
Proxy.revocable()
Proxy.revocable() 方法可以用来创建一个可撤销的代理对象。
语法:Proxy.revocable(target, handler)
target:将用Proxy封装的目标对象。可以是任何类型的对象,包括原生数组,函数,甚至可以是另外一个代理对象。handler:一个对象,其属性是一批可选的函数,这些函数定义了对应的操作被执行时代理的行为。
handler 对象的方法
handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。
所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。
handler.get()
handler.get() 方法用于拦截对象的读取属性操作。
语法:
new Proxy(target, {get(target, property, receiver) {},
});
参数:
target:目标对象property:被获取的属性名receiver:Proxy 或者继承 Proxy 的对象
返回:返回任何值
该方法会拦截目标对象的以下操作:
- 访问属性:
proxy[foo] 和proxy.bar - 访问原型链上的属性:
Object.create(proxy)[foo] Reflect.get()
如果违背了以下的约束,proxy 会抛出 TypeError:
- 如果要访问的目标属性是不可写以及不可配置的,则返回的值必须与该目标属性的值相同
- 如果要访问的目标属性没有配置访问方法,即 get 方法是 undefined 的,则返回值必须为 undefined
handler.set()
handler.set() 方法是设置属性值操作的捕获器。
语法:
new Proxy(target, {set(target, property, value, receiver) {}
});
参数:
target:目标对象property:被获取的属性名- value:新属性值
receiver:Proxy 或者继承 Proxy 的对象
返回:返回一个布尔值
- 返回
true代表属性设置成功 - 在严格模式下,如果
set()方法返回false,那么会抛出一个TypeError异常
该方法会拦截目标对象的以下操作:
- 指定属性值:
proxy[foo] = bar和proxy.foo = bar - 指定继承者的属性值:
Object.create(proxy)[foo] = bar Reflect.set()
如果违背以下的约束条件,proxy 会抛出一个 TypeError 异常:
- 若目标属性是一个不可写及不可配置的数据属性,则不能改变它的值
- 如果目标属性没有配置存储方法,即
[[Set]]属性的是undefined,则不能设置它的值 - 在严格模式下,如果
set()方法返回false,那么也会抛出一个TypeError异常
handler.has()
handler.has() 方法是针对 in 操作符的代理方法。
语法:
new Proxy(target, {has(target, prop) {},
});
参数:
target:目标对象prop:需要检查是否存在的属性
返回:返回一个 boolean 属性的值
这个钩子可以拦截下面这些操作:
- 属性查询:
foo in proxy - 继承属性查询:
foo in Object.create(proxy) with检查: with(proxy) { (foo); }Reflect.has()
如果违反了下面这些规则,proxy 将会抛出 TypeError:
- 如果目标对象的某一属性本身不可被配置,则该属性不能够被代理隐藏。
- 如果目标对象为不可扩展对象,则该对象的属性不能够被代理隐藏
handler.apply()
handler.apply() 方法用于拦截函数的调用。
语法:
new Proxy(target, {apply(target, thisArg, argumentsList) {},
});
参数:
target:目标对象(函数)thisArg:被调用时的上下文对象argumentsList:被调用时的参数数组
返回:返回任何值
该方法会拦截目标对象的以下操作:
proxy(...args)Function.prototype.apply()和Function.prototype.call()Reflect.apply()
handler.construct()
handler.construct() 方法用于拦截 new 操作符。为了使 new 操作符在生成的 Proxy 对象上生效,用于初始化代理的目标对象自身必须具有 [[Construct]] 内部方法(即 new target 必须是有效的)。
语法:
new Proxy(target, {construct(target, argumentsList, newTarget) {},
});
参数:
target:目标对象argumentsList:constructor 的参数列表newTarget:最初被调用的构造函数,就上面的例子而言是 p
返回:返回一个对象
该拦截器可以拦截以下操作:
new proxy(...args)Reflect.construct()
如果违反以下约定,代理将会抛出错误 TypeError:
- 必须返回一个对象
handler.deleteProperty()
handler.deleteProperty() 方法用于拦截对对象属性的 delete 操作。
语法:
new Proxy(target, {deleteProperty(target, property) {},
});
参数:
target:目标对象property:被获取的属性名
返回:返回一个 Boolean 类型的值,表示了该属性是否被成功删除
该方法会拦截以下操作:
- 删除属性:
delete proxy[foo]和delete proxy.foo Reflect.deleteProperty()
如果违背了以下不变量,proxy 将会抛出一个 TypeError:
- 如果目标对象的属性是不可配置的,那么该属性不能被删除。
handler.ownKeys()
handler.ownKeys() 方法用于拦截 Reflect.ownKeys()。
语法:
new Proxy(target, {ownKeys(target) {},
});
参数:
target:目标对象
返回:返回一个可枚举对象
该拦截器可以拦截以下操作::
Object.getOwnPropertyNames()Object.getOwnPropertySymbols()Object.keys()Reflect.ownKeys()
如果违反了下面的约束,proxy 将抛出错误 TypeError:
ownKeys的结果必须是一个数组- 数组的元素类型要么是一个
String,要么是一个Symbol - 结果列表必须包含目标对象的所有不可配置(non-configurable)、自有(own)属性的 key
- 如果目标对象不可扩展,那么结果列表必须包含目标对象的所有自有(own)属性的 key,不能有其他值
handler.getPrototypeOf()
handler.getPrototypeOf() 是一个代理(Proxy)方法,当读取代理对象的原型时,该方法就会被调用。
语法:
new Proxy(target, {getPrototypeOf(target) {}
})
参数:
- target:被代理的目标对象。
返回:返回一个对象或者 null。
这个方法可以拦截以下操作:
Object.getPrototypeOf()Reflect.getPrototypeOf()Object.prototype.__proto__Object.prototype.isPrototypeOf()instanceof
如果遇到了下面情况,JS 引擎会抛出 TypeError 异常:
getPrototypeOf()方法返回的不是对象也不是null- 目标对象是不可扩展的,且
getPrototypeOf()方法返回的原型不是目标对象本身的原型
handler.setPrototypeOf()
handler.setPrototypeOf() 方法主要用来拦截 Object.setPrototypeOf().
语法:
new Proxy(target, {setPrototypeOf(target, prototype) {}
})
参数:
target:被拦截目标对象prototype:对象新原型或为null
返回:如果成功修改了[[Prototype]],返回 true,否则返回 false
这个方法可以拦截以下操作:
Object.setPrototypeOf()Reflect.setPrototypeOf()
如果遇到了下面情况,JS 引擎会抛出 TypeError 异常:
- 如果
target不可扩展,原型参数必须与Object.getPrototypeOf(target)的值相同
handler.isExtensible()
handler.isExtensible() 方法用于拦截对对象的 Object.isExtensible()。
语法:
new Proxy(target, {isExtensible(target) {}
})
参数:
target:目标对象
返回:返回一个 Boolean 值或可转换成 Boolean 的值
这个方法可以拦截以下操作:
Object.isExtensible()Reflect.isExtensible()
如果遇到了下面情况,JS 引擎会抛出 TypeError 异常:
Object.isExtensible(proxy)必须同Object.isExtensible(target)返回相同值
handler.preventExtensions()
handler.preventExtensions() 方法用于设置对 Object.preventExtensions() 的拦截。
语法:
new Proxy(target, {preventExtensions(target) {}
})
参数:
target:所要拦截的目标对象
返回:返回一个布尔值
这个方法可以拦截以下操作:
Object.preventExtensions()Reflect.preventExtensions()
如果遇到了下面情况,JS 引擎会抛出 TypeError 异常:
- 如果目标对象是可扩展的,那么只能返回 false
handler.getOwnPropertyDescriptor()
handler.getOwnPropertyDescriptor() 方法是 Object.getOwnPropertyDescriptor() 的钩子。
语法:
new Proxy(target, {getOwnPropertyDescriptor(target, prop) {}
})
参数:
target:所要拦截的目标对象- prop:返回属性名称的描述
返回:返回一个 object 或 undefined
这个方法可以拦截以下操作:
Object.getOwnPropertyDescriptor()Reflect.getOwnPropertyDescriptor()
如果下列不变量被违反,代理将抛出一个 TypeError:
getOwnPropertyDescriptor必须返回一个 object 或undefined。- 如果属性作为目标对象的不可配置的属性存在,则该属性无法报告为不存在。
- 如果属性作为目标对象的属性存在,并且目标对象不可扩展,则该属性无法报告为不存在。
- 如果属性不存在作为目标对象的属性,并且目标对象不可扩展,则不能将其报告为存在。
- 属性不能被报告为不可配置,如果它不作为目标对象的自身属性存在,或者作为目标对象的可配置的属性存在。
- Object.getOwnPropertyDescriptor(target)的结果可以使用 Object.defineProperty 应用于目标对象,也不会抛出异常。
handler.defineProperty()
handler.defineProperty() 用于拦截对象的 Object.defineProperty() 操作。
语法:
new Proxy(target, {defineProperty(target, property, descriptor) {}
})
参数:
target:目标对象property:待检索其描述的属性名descriptor:待定义或修改的属性的描述符
返回:返回 Boolean,表示定义该属性的操作成功与否
该方法会拦截目标对象的以下操作:
Object.defineProperty()Reflect.defineProperty()proxy.property='value'
如果违背了以下的不变量,proxy 会抛出 TypeError:
- 如果目标对象不可扩展,将不能添加属性
- 不能添加或者修改一个属性为不可配置的,如果它不作为一个目标对象的不可配置的属性存在的话
- 如果目标对象存在一个对应的可配置属性,这个属性可能不会是不可配置的
- 如果一个属性在目标对象中存在对应的属性,那么
Object.defineProperty(target, prop, descriptor)将不会抛出异常 - 在严格模式下,
false作为handler.defineProperty方法的返回值的话将会抛出TypeError异常
Reflect
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 proxy.handler 的方法相同。
Reflect 不是一个函数对象,因此它是不可构造的。