handler.apply(target, thisArg, argumentsList)
用于拦截函数的调用。
target:目标对象(函数)。
thisArg:被调用时的上下文对象。
argumentsList:被调用时的参数数组。
apply方法可以返回任何值。
如果违反了以下约束,代理将抛出一个TypeError:
target必须是可被调用的。也就是说,它必须是一个函数对象。
handler.construct(target, argumentsList, newTarget)
用于拦截new 操作符. 为了使new操作符在生成的Proxy对象上生效,用于初始化代理的目标对象自身必须具有[[Construct]]内部方法(即 new target 必须是有效的)。
target:目标对象。
argumentsList:constructor的参数列表。
newTarget:最初被调用的构造函数。
construct 方法必须返回一个对象。
如果违反以下约定,代理将会抛出错误 TypeError:
必须返回一个对象.
var p = new Proxy(function() {}, {
construct: function(target, argumentsList, newTarget) {
return 1;
}
});
new p(); // TypeError is thrown
handler.defineProperty(target, property, descriptor)
用于拦截对对象的 Object.defineProperty() 操作
target:目标对象。
property:待检索其描述的属性名。
descriptor:待定义或修改的属性的描述符。
如果违背了以下的不变量,proxy会抛出 TypeError:
- 如果目标对象不可扩展, 将不能添加属性。
- 不能添加或者修改一个属性为不可配置的,如果它不作为一个目标对象的不可配置的属性存在的话。
- 如果目标对象存在一个对应的可配置属性,这个属性可能不会是不可配置的。
- 如果一个属性在目标对象中存在对应的属性,那么 Object.defineProperty(target, prop, descriptor) 将不会抛出异常。
- 在严格模式下, false 作为 handler.defineProperty 方法的返回值的话将会抛出 TypeError 异常.
当调用 Object.defineProperty() 或者 Reflect.defineProperty(),传递给defineProperty的descriptor有一个限制 - 只有以下属性才有用,非标准的属性将会被无视 :
enumerable
configurable
writable
value
get
set
var p = new Proxy({}, {
defineProperty(target, prop, descriptor) {
console.log(descriptor);
return Reflect.defineProperty(target, prop, descriptor);
}
});
Object.defineProperty(p, 'name', {
value: 'proxy',
type: 'custom'
}); // { value: 'proxy' }
handler.deleteProperty(target, property)
用于拦截对对象属性的 delete 操作
target:目标对象。
property:待删除的属性名。
deleteProperty 必须返回一个Boolean类型的值,表示了该属性是否被成功删除。
如果违背了以下不变量,proxy 将会抛出一个 TypeError:
- 如果目标对象的属性是不可配置的,那么该属性不能被删除。
handler.get(target, property, receiver)
用于拦截对象的读取属性操作。
target:目标对象。
property:被获取的属性名。
receiver:Proxy或者继承Proxy的对象
如果违背了以下的约束,proxy会抛出 TypeError:
- 如果要访问的目标属性是不可写以及不可配置的,则返回的值必须与该目标属性的值相同。
- 如果要访问的目标属性没有配置访问方法,即get方法是undefined的,则返回值必须为undefined。
var obj = {};
Object.defineProperty(obj, "a", {
configurable: false,
enumerable: false,
value: 10,
writable: false
});
var p = new Proxy(obj, {
get: function(target, prop) {
return 20;
}
});
p.a; //会抛出TypeError
handler.getOwnPropertyDescriptor(target, prop)
Object.getOwnPropertyDescriptor()的钩子。
target:目标对象。
prop:返回属性名称的描述。
getOwnPropertyDescriptor 方法必须返回一个object或undefined。
如果下列不变量被违反,代理将抛出一个 TypeError:
- getOwnPropertyDescriptor 必须返回一个 object 或 undefined。
- 如果属性作为目标对象的不可配置的属性存在,则该属性无法报告为不存在。
- 如果属性作为目标对象的属性存在,并且目标对象不可扩展,则该属性无法报告为不存在。
- 如果属性不存在作为目标对象的属性,并且目标对象不可扩展,则不能将其报告为存在。
- 属性不能被报告为不可配置,如果它不作为目标对象的自身属性存在,或者作为目标对象的可配置的属性存在。
- Object.getOwnPropertyDescriptor(target)的结果可以使用 Object.defineProperty 应用于目标对象,也不会抛出异常。
handler.getPrototypeOf(target)
是一个代理(Proxy)方法,当读取代理对象的原型时,该方法就会被调用。
getPrototypeOf 方法的返回值必须是一个对象或者null。
在JavaScript中,下面这五种操作(方法/属性/运算符)可以触发JS引擎读取一个对象的原型,也就是可以触发 getPrototypeOf() 代理方法的运行:
- Object.getPrototypeOf()
- Reflect.getPrototypeOf()
- proto
- Object.prototype.isPrototypeOf()
- instanceof
如果遇到了下面两种情况,JS 引擎会抛出 TypeError 异常:
- getPrototypeOf() 方法返回的不是对象也不是 null。
- 目标对象是不可扩展的,且getPrototypeOf()方法返回的原型不是目标对象本身的原型。
5种触发getPrototypeOf代理方法的方式
var obj = {};
var p = new Proxy(obj, {
getPrototypeOf(target) {
return Array.prototype;
}
});
console.log(
Object.getPrototypeOf(p) === Array.prototype, // true
Reflect.getPrototypeOf(p) === Array.prototype, // true
p.__proto__ === Array.prototype, // true
Array.prototype.isPrototypeOf(p), // true
p instanceof Array // true
);
两种情况下的异常
var obj = {};
var p = new Proxy(obj, {
getPrototypeOf(target) {
return "foo";
}
});
Object.getPrototypeOf(p); // TypeError: "foo" is not an object or null
var obj = Object.preventExtensions({});
var p = new Proxy(obj, {
getPrototypeOf(target) {
return {};
}
});
Object.getPrototypeOf(p); // TypeError: expected same prototype value
handler.has(target, prop)
是针对 in 操作符的代理方法。
has方法返回一个boolean属性的值.
如果违反了下面这些规则, proxy将会抛出TypeError:
- 如果目标对象的某一属性本身不可被配置,则该属性不能够被代理隐藏.
- 如果目标对象为不可扩展对象,则该对象的属性不能够被代理隐藏
handler.isExtensible(target)
handler.isExtensible() 方法用于拦截对对象的Object.isExtensible()。
isExtensible方法必须返回一个 Boolean值或可转换成Boolean的值。
如果违背了以下的约束,proxy会抛出 TypeError:
- Object.isExtensible(proxy) 必须同Object.isExtensible(target)返回相同值。也就是必须返回true或者为true的值,返回false和为false的值都会报错。
var p = new Proxy({}, {
isExtensible: function(target) {
return false;//return 0;return NaN等都会报错
}
});
Object.isExtensible(p); // TypeError is thrown
handler.ownKeys(target)
用于拦截 Reflect.ownKeys().
ownKeys方法必须返回一个可枚举对象.
该拦截器可以拦截以下操作::
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.keys()
Reflect.ownKeys()
如果违反了下面的约束,proxy将抛出错误 TypeError:
- ownKeys 的结果必须是一个数组.
- 数组的元素类型要么是一个 String ,要么是一个 Symbol.
- 结果列表必须包含目标对象的所有不可配置(non-configurable )、自有(own)属性的key.
- 如果目标对象不可扩展,那么结果列表必须包含目标对象的所有自有(own)属性的key,不能有其它值.
handler.preventExtensions(target)
用于设置对Object.preventExtensions()的拦截
preventExtensions方法返回一个布尔值.
这个trap可以拦截这些操作:
Object.preventExtensions()
Reflect.preventExtensions()
如果违反了下列规则, proxy则会抛出一个 TypeError:
- 如果目标对象是可扩展的,那么只能返回false
handler.set(target, property, value, receiver)
以下是传递给 set() 方法的参数。this 绑定在 handler 对象上。
target:目标对象。
property:将被设置的属性名或 Symbol。
value:新属性值。
receiver:最初被调用的对象。通常是 proxy 本身,但 handler 的 set 方法也有可能在原型链上,或以其他方式被间接地调用(因此不一定是 proxy 本身)。
比如:假设有一段代码执行 obj.name = "jen", obj不是一个 proxy,且自身不含 name 属性,但是它的原型链上有一个 proxy,那么,那个 proxy 的 set() 处理器会被调用,而此时,obj 会作为 receiver 参数传进来。
set() 方法应当返回一个布尔值。
返回 true 代表属性设置成功。
在严格模式下,如果 set() 方法返回 false,那么会抛出一个 TypeError 异常。
如果违背以下的约束条件,proxy 会抛出一个 TypeError 异常:
- 若目标属性是一个不可写及不可配置的数据属性,则不能改变它的值。
- 如果目标属性没有配置存储方法,即 [[Set]] 属性的是 undefined,则不能设置它的值。
- 在严格模式下,如果 set() 方法返回 false,那么也会抛出一个 TypeError 异常。
handler.setPrototypeOf(target, prototype)
主要用来拦截 Object.setPrototypeOf().
如果成功修改了[[Prototype]], setPrototypeOf 方法返回 true,否则返回 false.
如果违反了下列规则,则proxy将抛出一个TypeError:
- 如果 target 不可扩展, 原型参数必须与Object.getPrototypeOf(target) 的值相同.
- 如果你不想为你的对象设置一个新的原型,你的handler's的setPrototypeOf方法可以返回false,也可以抛出异常。