代理捕获器与反射方法
资料来源JavaScript高级程序设计
代理可以捕获13种不同的基本操作。这些基本操作有各自不同的反射API方法、参数、关联ECMAScript操作和不变式。
文章目录
get()
get()捕获器会在获取属性值的操作种被调用。对应的反射API的方法为Reflect.get()
// get()
const test1={
name:'yihen'
}
const proxy=new Proxy(test1,{
get(target,property,receiver){
console.log('已经调用了get()')
return Reflect.get(...arguments);
}
})
//已经调用了get()
console.log(proxy.name);// yihen
- 返回值
返回值无限制
- 拦截的操作
- proxy.property
- proxy[property]
- Object.create(proxy)[property]
- Reflect.get(proxy,property,receiver)
- 捕获器处理程序参数
- target : 目标对象
- property: 引用的目标对象上的字符串键属性
- receiver:代理对象或继承代理对象的对象
- 捕获器不变式
-
如果target.property不可写且不可配置,则处理程序返回的值必须与target.property匹配
-
如果target.property不可配置且[[Get]]特性为undefined,处理程序的返回值也必须是undefined
set()
set()捕获器会在设置属性值的操作中被调用。对应的反射API方法为Reflect.set()
const test2={}
const proxy2=new Proxy(test2,{
set(target,property,value,receiver){
console.log("已经调用了set()")
const res=Reflect.set(...arguments);
console.log(res);// true
return res
}
})
proxy2.name='yihen';// 已经调用了set()
console.log(test2.name); //yihen
-
返回值
返回true表示成功;返回false表示失败,严格模式下会抛出TypeError -
拦截操作
- proxy.property=value;
- proxy[property]=value;
- Object.create(proxy)[value];
- Reflect.set(taget,property,value,receiver)
- 捕获器处理程序参数
- target: 目标对象
- property: 引用的目标对象上的字符串键属性
- value: 要赋给属性的值
- receiver: 接收最初赋值的对象
- 捕获器不变式
-
如果target.property不可写且不可配置,则不能修改目标的属性值
-
如果target.property不可配置且[[Set]]特性为undefined,则不能修改目标属性的值,在严格模式下,处理程序中返回false会抛出TypeError
has()
has()捕获器会在in操作符中被调用,对应的反射API方法为Reflect.has();
/*
has()
*/
const test3={}
const proxy3=new Proxy(test3,{
has(target,property){
console.log("你调用了has()")
return Reflect.has(...arguments)
}
})
console.log("name" in proxy3);// false
proxy3.name='yihen'
console.log("name" in proxy3);// true
-
返回值
has()必须返回bool值,表示属性是否存在,返回非bool值会被转换为bool值 -
拦截操作
- property in proxy
- property in Object.create(proxy)
- with(proxy){(property);}
- Reflect.has(proxy,property)
- 捕获器处理程序参数
- target: 目标对象
- property: 引用的目标对象上的字符串键属性
- 捕获器不变式
-
如果target.property存在且不可配置,则处理程序必须返回true
-
如果target.property存在且目标对象不可扩展,则处理程序必须返回true
defineProperty
defineProperty()捕获器会在Object.defineProperty()中被调用。对应的反射API方法为Reflect.defineProperty().
/*
defineProperty()
*/
const test4={}
const proxy4=new Proxy(test4,{
defineProperty(target,property,descriptor){
console.log('你调用了defineProperty');
return Reflect.defineProperty(...arguments)
}
});
Object.defineProperty(proxy4,'name',{
value:'yihen'
});//你调用了defineProperty
- 返回值
defineProperty() 必须返回bool值,表示属性是否成功定义。返回非bool值会被转换为bool值
- 拦截操作
- Object.defineProperty(proxy,property,descriptor)
- Reflect.defineProperty(proxy,property,descriptor)
- 捕获器处理程序参数
- target: 目标对象
- property: 引用的目标对象上的字符串键属性
- descriptor: 包含可选的 enumerable、configurable、writable、value、get和set定义的对象
- 捕获器不变式
- 如果目标对象不可扩展,则无法定义属性
- 如果目标对象有一个可配置的属性,则不能添加同名的不可配置属性
- 如果目标对象有一个不可配置的属性,则不能添加同名的可配置属性
getOwnPropertyDescriptor()
getOwnPropertyDescriptor()捕获器会在 Object.getOwnPropertyDescriptor()中被调用。对应的反射API方法为Reflect.getOwnPropertyDescriptor()
/*
getOwnPropertyDescriptor()
*/
const test5={name:'yihen'}
const proxy5=new Proxy(test5,{
getOwnPropertyDescriptor(target,property){
console.log('你调用了getOwnPropertyDescriptor')
return Reflect.getOwnPropertyDescriptor(...arguments)
}
})
const res= Object.getOwnPropertyDescriptor(proxy5,'name') // '你调用了getOwnPropertyDescriptor'
console.log(res)
/*
{
value: 'yihen',
writable: true,
enumerable: true,
configurable: true
}
*/
-
返回值
getOwnPropertyDescriptor()必须返回对象,或者在属性不存在的时候返回undefined -
拦截的操作
- Object.getOwnpropertyDescriptor(proxy,property)
- Reflect.getOwnPropertyDescriptor(proxy,property)
- 捕获器处理程序参数
- target: 目标对象
- property: 引用的目标对象上的字符串键属性
- 捕获器的不变式
-
如果自有的target.property存在且不可配置,则处理程序必须返回一个表示该属性存在的对象
-
如果自有的target.property存在且可配置,则处理程序必须返回一个表示该属性存在且可配置的对象
-
如果target.property不存在且target不可扩展,则处理程序必须返回undefined表示该属性不存在
-
如果target.property不存在,则处理程序不能返回表示该属性可配置的对象
deleteProperty()
deleteProperty()捕获器会在delete操作符中被调用。对应的反射API方法为Reflect.deleteProperty()。
/*
deleteProperty()
*/
const test6={name:'yihen'}
const proxy6=new Proxy(test6,{
deleteProperty(target,property){
console.log('你调用了deleteProperty()')
return Reflect.deleteProperty(...arguments)
}
})
console.log(proxy6.name);// yihen
delete proxy6.name;
console.log(proxy6.name);// undefined
- 返回值
deleteProperty()返回值必须是bool值,表示删除属性是否成功。返回非bool值会被转换为bool值
- 拦截操作
- delete proxy.property
- delete proxy[property]
- Reflect.deleteProperty(proxy,property)
- 捕获器处理程序参数
- target: 目标对象
- property: 引用的目标对象上的字符串键属性
- 捕获器不变式
如果自有的target.property存在不可配置,则处理函数不能删除这个属性
ownKeys()
onwKeys()捕获器会在Object.keys()及类似的方法中被调用。对应的反射API方法为Reflect.ownKeys()
/*
ownKeys()
*/
const test7={name:'yihen',age:18}
Object.defineProperty(test7,'id',{
value:12345678
})
const proxy7=new Proxy(test7,{
ownKeys(target){
console.log('你调用了ownKeys()')
const res=Reflect.ownKeys(...arguments)
console.log(res);// [ 'name', 'age','id ]
return res
}
})
const res2=Object.keys(proxy7)
console.log(res2);// [ 'name', 'age' ]
- 返回值
ownKeys()必须返回包含字符串或符号的可枚举对象
- 拦截的操作
- Object.getOwnPropertyNames(proxy);
- Object.getOwnPropertySymbols(proxy);
- Object.keys(proxy);
- Reflect.ownKeys(proxy)
- 捕获器处理程序参数
target: 目标对象
- 捕获器不变式
- 返回的可枚举对象必须包含target的所有不可配置的自有属性
- 如果target不可扩展,则返回可枚举对象必须准确的包含自有属性键
getPrototypeOf()
getPrototypeOf()捕获器会在Object.getPrototypeOf()中被调用。对应的反射API方法为Reflect.getPrototypeOf()。
/*
getPrototypeOf()
*/
const test8={}
const proxy8=new Proxy(test8,{
getPrototypeOf(target){
console.log("你调用了了getPrototypeOf()")
const res=Reflect.getPrototypeOf(...arguments);
console.log(res);//[Object: null prototype] {}
return res
}
})
console.log(Object.getPrototypeOf(proxy8));//[Object: null prototype] {}
- 返回值
getPrototypeOf()必须返回对象或null
- 拦截的操作
- Object.getPrototypeOf(proxy);
- proxy.__proro__
- Object.prototypeOf.isPrototypeOf(proxy)
- proxy instanceof Object
- Reflect.getPrototypeOf(proxy)
- 捕获处理程序参数
- target: 目标对象
- 捕获不变式
如果target不可拓展,则Object.getPrototype(proxy)唯一有效的返回值就是Object.getPrototypeOf(target)的返回值
setPrototypeOf()
setPrototypeOf()捕获器会在Object.setPrototypeOf()中被调用,对应的反射API方法为Reflect.setPrototypeOf()
/*
setPrototypeOf()
*/
const test9={}
const proxy9=new Proxy(test9,{
setPrototypeOf(target,property){
console.log('你调用了setPrototypeOf()')
const res=Reflect.setPrototypeOf(...arguments);
console.log(res); // true
return res
}
})
Object.setPrototypeOf(proxy9,Object);
- 返回值
setPrototypeOf()必须返回bool值,表示原型赋值是否成功,返回非bool值会被转换为bool值
- 拦截的操作
- Object.setPrototypeOf(proxy)
- Reflect.setPrototypeOf(proxy)
- 捕获器处理程序参数
- target: 目标对象
- prototype: target的替代原型,如果是*原型则为null
- 捕获器不定式
如果target不可扩展,则唯一有效的prototype参数就是Object.getPrototypeOf(target)
isExtensible()
isExtensible()捕获器会在Object.isExtensible()中被调用。对应的反射API方法为Reflect.isExtensible()。
const test1={}
const proxy1=new Proxy(test1,{
isExtensible(target){
console.log("正在调用isExtensible()");
const res=Reflect.isExtensible(...arguments);
console.log(res);// true
return res
}
})
console.log(Object.isExtensible(proxy1));//true
-
返回值
isExtensible()必须返回bool值,表示target是否可扩展。返回非bool值会被转换为bool值。 -
拦截的操作
- Object.isExtensible(proxy)
- Reflect.isExtensible(proxy)
- 捕获处理程序参数
- target: 目标对象
- 捕获器不变式
- 如果target可扩展,必须返回true
- 如果target不可扩展,必须返回false
preventExtensions()
preventExtensions()捕获器会在Object.preventExtensions()中被调用。对应的反射API方法为Reflect.preventExtensions()
/*
preventExtensions()
*/
const test2={}
const proxy2=new Proxy(test2,{
preventExtensions(target){
console.log('你调用了preventExtensions()')
const res=Reflect.preventExtensions(...arguments)
console.log(res);// true
return res
}
})
console.log(Object.preventExtensions(proxy2));// {}
- 返回值
preventExtensions()必须返回bool值,表示target是否应该不可扩展,返回非bool值会被转换为bool值
- 拦截的操作
- Object.preventExtensions(proxy)
- Reflect.preventExtensions(proxy)
- 捕获器处理程序操作
target;目标对象
- 捕获其不变式
如果Object.isExtensible(proxy)是false,则处理程序必须返回true
apply
apply()捕获器会在调用函数时中被调用。对应的反射API方法为Reflect.apply()
/*
apply()
*/
const test3=()=>{}
const proxy3=new Proxy(test3,{
apply(target,thisArg,...argumentsList){
console.log('你调用了apply()')
const res=Reflect.apply(...arguments)
console.log(res);// undefined
return res
}
})
proxy3()
- 返回值
返回值无限制
- 拦截的操作
- proxy(…arguments)
- Function.prototype.apply(thisArg,argumentsList)
- Function.prototype.call(thisArg,…argumentsList)
- Reflect.apply(target,thisArg,argumentsList)
- 捕获器处理程序参数
- target: 目标对象
- thisArg: 调用函数时的this参数
- argumentsList: 调用函数时的参数列表
- 捕获器不变式
- target必须时一个函数对象
construct()
construct()捕获器会在new操作符中被调用。对应的反射API方法为Reflect.construct()
/*
construct()
*/
const test4=function(){}
const proxy4=new Proxy(test4,{
construct(target,argumentsList,newTarget){
console.log('你调用了construct()');
const res=Reflect.construct(...arguments)
console.log(res);//test4 {}
return res
}
})
new proxy4;
- 返回值
construct()必须返回一个对象
- 拦截操作
- new proxy(…argumentsList)
- Reflect.construct(target,argumentsList,newTarget)
- 捕获器处理程序参数
- target: 目标构造函数
- argumentsList: 传给目标构造函数的参数列表
- newTarget: 最初被调用的构造函数
- 捕获器不变式
target必须可以用作构造函数