代理捕获器与反射方法

代理捕获器与反射方法

资料来源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
  1. 返回值

返回值无限制

  1. 拦截的操作
  • proxy.property
  • proxy[property]
  • Object.create(proxy)[property]
  • Reflect.get(proxy,property,receiver)
  1. 捕获器处理程序参数
  • target : 目标对象
  • property: 引用的目标对象上的字符串键属性
  • receiver:代理对象或继承代理对象的对象
  1. 捕获器不变式
  • 如果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
  1. 返回值
    返回true表示成功;返回false表示失败,严格模式下会抛出TypeError

  2. 拦截操作

  • proxy.property=value;
  • proxy[property]=value;
  • Object.create(proxy)[value];
  • Reflect.set(taget,property,value,receiver)
  1. 捕获器处理程序参数
  • target: 目标对象
  • property: 引用的目标对象上的字符串键属性
  • value: 要赋给属性的值
  • receiver: 接收最初赋值的对象
  1. 捕获器不变式
  • 如果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
  1. 返回值
    has()必须返回bool值,表示属性是否存在,返回非bool值会被转换为bool值

  2. 拦截操作

  • property in proxy
  • property in Object.create(proxy)
  • with(proxy){(property);}
  • Reflect.has(proxy,property)
  1. 捕获器处理程序参数
  • target: 目标对象
  • property: 引用的目标对象上的字符串键属性
  1. 捕获器不变式
  • 如果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
  1. 返回值

defineProperty() 必须返回bool值,表示属性是否成功定义。返回非bool值会被转换为bool值

  1. 拦截操作
  • Object.defineProperty(proxy,property,descriptor)
  • Reflect.defineProperty(proxy,property,descriptor)
  1. 捕获器处理程序参数
  • target: 目标对象
  • property: 引用的目标对象上的字符串键属性
  • descriptor: 包含可选的 enumerable、configurable、writable、value、get和set定义的对象
  1. 捕获器不变式
  • 如果目标对象不可扩展,则无法定义属性
  • 如果目标对象有一个可配置的属性,则不能添加同名的不可配置属性
  • 如果目标对象有一个不可配置的属性,则不能添加同名的可配置属性

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
}
*/
  1. 返回值
    getOwnPropertyDescriptor()必须返回对象,或者在属性不存在的时候返回undefined

  2. 拦截的操作

  • Object.getOwnpropertyDescriptor(proxy,property)
  • Reflect.getOwnPropertyDescriptor(proxy,property)
  1. 捕获器处理程序参数
  • target: 目标对象
  • property: 引用的目标对象上的字符串键属性
  1. 捕获器的不变式
  • 如果自有的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
  1. 返回值

deleteProperty()返回值必须是bool值,表示删除属性是否成功。返回非bool值会被转换为bool值

  1. 拦截操作
  • delete proxy.property
  • delete proxy[property]
  • Reflect.deleteProperty(proxy,property)
  1. 捕获器处理程序参数
  • target: 目标对象
  • property: 引用的目标对象上的字符串键属性
  1. 捕获器不变式

如果自有的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' ]
  1. 返回值

ownKeys()必须返回包含字符串或符号的可枚举对象

  1. 拦截的操作
  • Object.getOwnPropertyNames(proxy);
  • Object.getOwnPropertySymbols(proxy);
  • Object.keys(proxy);
  • Reflect.ownKeys(proxy)
  1. 捕获器处理程序参数

target: 目标对象

  1. 捕获器不变式
  • 返回的可枚举对象必须包含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] {}
  1. 返回值

getPrototypeOf()必须返回对象或null

  1. 拦截的操作
  • Object.getPrototypeOf(proxy);
  • proxy.__proro__
  • Object.prototypeOf.isPrototypeOf(proxy)
  • proxy instanceof Object
  • Reflect.getPrototypeOf(proxy)
  1. 捕获处理程序参数
  • target: 目标对象
  1. 捕获不变式

如果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);
  1. 返回值

setPrototypeOf()必须返回bool值,表示原型赋值是否成功,返回非bool值会被转换为bool值

  1. 拦截的操作
  • Object.setPrototypeOf(proxy)
  • Reflect.setPrototypeOf(proxy)
  1. 捕获器处理程序参数
  • target: 目标对象
  • prototype: target的替代原型,如果是*原型则为null
  1. 捕获器不定式

如果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
  1. 返回值
    isExtensible()必须返回bool值,表示target是否可扩展。返回非bool值会被转换为bool值。

  2. 拦截的操作

  • Object.isExtensible(proxy)
  • Reflect.isExtensible(proxy)
  1. 捕获处理程序参数
  • target: 目标对象
  1. 捕获器不变式
  • 如果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));// {}
  1. 返回值

preventExtensions()必须返回bool值,表示target是否应该不可扩展,返回非bool值会被转换为bool值

  1. 拦截的操作
  • Object.preventExtensions(proxy)
  • Reflect.preventExtensions(proxy)
  1. 捕获器处理程序操作

target;目标对象

  1. 捕获其不变式

如果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()
  1. 返回值

返回值无限制

  1. 拦截的操作
  • proxy(…arguments)
  • Function.prototype.apply(thisArg,argumentsList)
  • Function.prototype.call(thisArg,…argumentsList)
  • Reflect.apply(target,thisArg,argumentsList)
  1. 捕获器处理程序参数
  • target: 目标对象
  • thisArg: 调用函数时的this参数
  • argumentsList: 调用函数时的参数列表
  1. 捕获器不变式
  • 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;
  1. 返回值

construct()必须返回一个对象

  1. 拦截操作
  • new proxy(…argumentsList)
  • Reflect.construct(target,argumentsList,newTarget)
  1. 捕获器处理程序参数
  • target: 目标构造函数
  • argumentsList: 传给目标构造函数的参数列表
  • newTarget: 最初被调用的构造函数
  1. 捕获器不变式

target必须可以用作构造函数

上一篇:C# 属性(Property)


下一篇:Spring之PropertyResourceConfigurer及其子类详解