Proxy格式:
let target = {}, handler = {};
let proxy = new Proxy(target, handler);
---
let obj = {};
let proxy = new Proxy(obj, {
// ...
})
外界每次通过Proxy访问target 对象的属性时,就会经过 handler 对象,因此,我们可以通过重写handler对象中的一些方法来做一些拦截的操作。
监听属性、参数及监听内容
属性值 | 监听器参数 | 监听内容 |
---|---|---|
has | target, prop | 监听 in 语句的使用 |
get | target, prop, reciver | 监听目标对象的属性读取 |
set | target, prop, value, reciver | 监听目标对象的属性赋值 |
deleteProperty | target, prop | 监听 delete 语句对目标对象的删除属性行为 |
ownKeys | target | 监听 Object.getOwnPropertyName() 的读取 |
apply | target, thisArg, arguments | 监听目标函数(作为目标对象)的调用行为 |
construct | target, arguments, newTarget | 监听目标构造函数作为目标对象 利用 new 而生成实例的行为 |
getPrototypeOf | target | 监听 Objext.getPrototypeOf() 的读取 |
setPrototypeOf | target, prototype | 监听 Objext.setPrototypeOf() 的调用 |
isExtensible | target | 监听 Objext.isExtensible() 的读取 |
preventExtensions | target | 监听 Objext.preventExtensions() 的读取 |
getOwnPropertyDescriptor | target, prop | |
defineProperty | target, property, descriptor | 监听 Object.defineProperty() 的调用 |
has
handler.has() 方法可以看作是针对 in 操作的钩子
var p = new Proxy(target, {
has: function(target, prop) {
}
});
-targe,目标对象 -prop,需要检查是否存在的属性 -this绑定到handler对象上 -返回一个boolean值
const p = new Proxy({}, {
has(target, prop){
console.log(`Checking "${prop}" is in the target or not`);
return true;
}
})
console.log('foo' in p);
// Checking "foo" is in the target or not
// true
约束,违背proxy会抛出一个TypeError: -如果目标对象的某一属性本身不可被配置,则该属性不能够被代理隐藏 -如果目标对象为不可扩展对象,则该对象的属性不能够被代理隐藏
get
handler.get() 方法用于拦截对象的读取属性操作。
var p = new Proxy(target, {
get: function(target, property, receiver) {
}
});
const obj = {foo: 1};
const p = new Proxy(obj, {
get(target, prop){
console.log(`Program is trying to fetch the property "${prop}".`);
return target[prop];
}
})
p.foo; // Program is trying to fetch the property "foo".
p.something; // Program is trying to fetch the property "something".
约束条件: -如果要访问的目标属性是不可写以及不可配置的,则返回的值必须与该目标属性的值相同。 -如果要访问的目标属性没有配置访问方法,即get方法是undefined的,则返回值必须为undefined。
set
handler.set() 方法用于拦截设置属性值的操作。
var p = new Proxy(target, {
set: function(target, property, value, receiver) {
}
});
-target,目标对象 -property,被设置的属性名 -value,被设置的新值 -receiver,最初被调用的对象。通常是proxy本身,但handler的set方法也有可能在原型链上或以其他方式被间接地调用 因此不一定是proxy本身
-this绑定到handler对象上 -返回一个布尔值,返回true代表此次设置属性成功了,如果返回false且设置属性操作发生在严格模式下,那么会抛出一个TypeError
const obj = {};
const p = new Proxy(obj, {
set(target, prop, value){
console.log(`Setting value "${value}" on the key "${prop}" in the target object`);
target[prop] = value;
return true;
}
})
p.foo = 1;
// Setting value "1" on the key "foo" in the target object
约束: -若目标属性是不可写及不可配置的,则不能改变它的值 -如果目标属性没有配置存储方法,即set方法是undefined的,则不能设置它的值 -在严格模式下,若set方法返回false,则会抛出一个 TypeError 异常
apply
handler.apply() 方法用于拦截函数的调用
var p = new Proxy(target, {
apply: function(target, thisArg, argumentsList) {
}
});
-target,目标对象 函数
-thisArg,被调用时的上下文对象 -argumentsList,被调用时的参数列表 -this绑定到handler对象 -可以返回任何值
const sum = function(...args){
return args
.map(Number)
.filter(Boolean)
.reduce((a, b) => a + b);
}
const p = new Proxy(sum, {
apply(target, thisArg, args){
console.log(`Function is being called with arguments [${args.join()}] and context ${thisArg}`);
return target.call(thisArg, ...args);
}
})
console.log(p(1, 2, 3));
// Function is being called with arguments [1,2,3] and context undefined
// 6
construct
handler.construct()用于来接new操作
var p = new Proxy(target, {
construct: function(target, argumentsList, newTarget) {
}
});
-target,目标对象 -argumensList,构造器参数列表 -newTarget,最初调用的构造函数 -this绑定到handler -返回一个对象
class Foo{};
const p = new Proxy(Foo, {
construct(target, args, newTarget){
return {arguments: args} // 这里返回的结果会是 new 所得到的实例}
})
const obj = new p(1, 2, 3);
console.log(obj.arguments); // [1, 2, 3]
约束: 返回值必须是一个对象