proxy.handler
- proxy.handler.get 拦截对象的读取属性操作。
- proxy.handler.set 拦截设置属性值的操作。
- proxy.handler.has 可以看作是针对
in操作的钩子. - proxy.handler.deleteProperty 拦截对对象属性的
delete操作。
let person = {
name: 'lcj',
height: 164,
age: 31,
hobby: 'reading',
};
let proxy = new Proxy(person, {
get: (target, propKey, selfProxy) => {
//目标对象、属性名和 proxy实例本身 (操作行为所针对的对象),最后一个参数可选。
return propKey in target ? target[propKey] : 'Error';
},
set: (target, propKey, value, selfProxy) => {
//目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。
if (propKey === 'height') {
if (!Number.isInteger(value)) {
throw new TypeError(`${value} is not an int`);
}
}
target[propKey] = value;
},
has: (target, propKey) => {//可以看作是针对 in操作的钩子.
//用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符。has()方法可以接受两个参数,分别是目标对象、需查询的属性名。
return target[propKey] ? true : false;
},
deleteProperty: (target, propKey) => {
//用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。deleteProperty() 方法接受两个参数:目标对象、目标属性
if (propKey == 'name') {
alert('name不可以删除');
} else {
delete target[propKey];
}
return true;
},
});
proxy.sex = '男';
proxy.height = 88;
// console.log(person);
// console.log('sex' in proxy); //true
// console.log('a' in proxy); //false
// delete proxy.name;
// delete proxy.age;
console.log(person); //没有了age属性
5.proxy.handler.apply 拦截函数的调用。
let person = () => 'i am the target';
let proxy = new Proxy(target, {
//apply方法拦截函数的调用、call和apply操作。apply方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组。
// apply: (target, ctx, args) => 'i am the proxy',
apply: (target, ctx, args) => {
return Math.max(...args);//返回参数的最大值
},
});
console.log(proxy(1, 2, 3));
6.proxy.handler.construct 用于拦截new操作. 为了使新的操作在生成的Proxy对象上有效,用于初始化代理的目标本身必须具有[[Construct]]内部方法(即new target必须是有效的)。
let person = function () {};
let proxy = new Proxy(person, {
construct: (target, args, cxt) => {//用于拦截new命令,下面是拦截对象的写法。construct()方法可以接受三个参数: 目标对象、构造函数的参数数组、目标对象的上下文对象(this)
//return new target(...args);//person {}
return args.map((i) => i * 2);
},
});
console.log(new proxy(1, 2, 3));//[2,4,6]
7.proxy.handler.defineProperty 拦截对对象的 Object.defineProperty() 操作。
8.proxy.handler.getOwnPropertyDescriptor 方法是Object.getOwnPropertyDescriptor() 的陷阱。
9.proxy.handler.getPrototypeOf 是一个代理方法,当读取代理对象的原型时,该方法就会被调用。
10.proxy.handler.setPrototypeOf 用来拦截Object.setPrototypeOf()
11.proxy.handler.isExtensible 拦截对对象的Object.isExtensible()
12.proxy.handler.preventExtensions 用来拦截Object.preventExtensions
13.proxy.handler.ownKeys 是一个Reflect.ownKeys()陷阱
const handler1 = {
defineProperty(target, propKey, descriptor) {//拦截对对象的 Object.defineProperty() 操作。
//目标对象 属性名称 正在定义或修改的属性的描述符。
//set方法在的时候无效
if (propKey[0] === '_') {
throw new Error(
`Invalid attempt to define private "${propKey}" property`,
);
}
return true;
},
getOwnPropertyDescriptor: (target, propKey) => {//方法是Object.getOwnPropertyDescriptor() 的陷阱。
// console.log(`called: ${propKey}`);
// Expected output: "called: eyeCount"
return { configurable: true, enumerable: true, value: 5 };
},
getPrototypeOf(target) {//是一个代理方法,当读取代理对象的原型时,该方法就会被调用。
return { eyeCount: 2 };
},
setPrototypeOf(target, prototype) {//用来拦截Object.setPrototypeOf()
//prototype: 对象新原型或为null
target.geneticallyModified = true;
return false;//成功修改了返回true否则返回false
},
isExtensible(target) {//拦截对对象的Object.isExtensible()
//可扩展的
return Reflect.isExtensible(target);
},
preventExtensions(target) {//用来拦截Object.preventExtensions
target.canEvolve = false;
return Reflect.preventExtensions(target);
},
ownKeys(target) {//是一个Reflect.ownKeys()陷阱
return Reflect.ownKeys(target);
},
};
const monster1 = {
eyeCount: 4,
canEvolve: true,
geneticallyModified: false,
[Symbol('secret')]: 'I am scared!',
};
const proxy1 = new Proxy(monster1, handler1);
// console.log((proxy1._secret = 'easily scared'));
// Expected output: Error: Invalid attempt to define private "_secret" property
console.log(Object.getOwnPropertyDescriptor(proxy1, 'eyeCount').value); //5
console.log(Object.getPrototypeOf(proxy1).eyeCount); //2
console.log(Object.isExtensible(proxy1)); //true
console.log(monster1.canEvolve); //true
Object.preventExtensions(proxy1);
console.log(Object.isExtensible(proxy1)); //false
console.log(monster1.canEvolve); //false
//设置原型上
console.log(Reflect.setPrototypeOf(proxy1, {})); //false
console.log(monster1.geneticallyModified); //true
console.log(Object.keys(proxy1)); //['eyeCount', 'canEvolve', 'geneticallyModified']
Proxy.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); // Cannot perform 'get' on a proxy that has been revoked
//proxy.foo = 1; // TypeError again
//delete proxy.foo; // still TypeError
//typeof proxy;//Error
一旦某个代理对象被撤销,它将变的几乎完全不可用,在它身上执行任何的可代理操作都会抛出TypeError异常(注意,可代理操作一共有14 种,执行这 14 种操作以外的操作不会抛出异常)。一旦被撤销,这个代理对象永远不可能恢复到原来的状态,同时和它关联的目标对象以及处理器对象将有可能被垃圾回收掉。调用撤销方法多次将不会有任何效果,当然,也不会报错。