JavaScript中的Proxy
前言
这个和之前的Reflect有一定的关系,也是Vue3实现的一个很重要的API,学学学。
Proxy
顾名思义,就是一个代理对象,通过一组配置函数来拦截操作从而使得以源对象得以被扩展。
Proxy是一个构造函数
由两个参数
obj需要代理的对象handler一组由特定的处理函数组成的对象,如果没有指定,则会使用源对象的默认行为。
1 | var o = {}; |
在Reflect上的方法,Proxy都可以拦截,具体包括
getPrototypeOfsetPrototypeOfisExtensiblepreventExtensiblegetOwnPropertyDescriptordefinePropertyhasgetsetdeletePropertyownKeysapplyconstruct
getPrototypeOf()
读取代理对象的原型时,这个方法就会调用
有一个参数
obj源对象
该函数必须返回一个对象或者null
1 | var o = {}; |
可以触发该函数的操作包括
Object.getPrototypeOfReflect.getPrototypeOf__proto__Object.prototype.isPrototypeOfinstanceof
1 | var proxy = new Proxy({},{ |
setPrototypeOf()
设置代理对象的原型时,这个方法就会调用。
有两个参数
obj源对象prototype将设置的原型对象
该函数在设置prototype成功返回true,失败返回false
1 | var proxy = new Proxy({},{ |
可以触发该函数的操作包括
Reflect.setProtytpeOfObject.setPrototypeOf
isExtensible()
查询代理对象是否可以扩展时,这个方法就会调用。
有一个参数
obj源对象
返回值必须为一个boolean值或者可以转为Boolean的值。
1 | var proxy = new Proxy({},{ |
可以触发该函数的操作包括
Reflect.isExtensibleObject.isExtensible
preventExtensions()
禁止代理对象扩展时,这个方法就会调用。
有一个参数
obj源对象
返回值必须为一个boolean值或者可以转为boolean的值。
1 | var proxy = new Proxy({},{ |
可以触发该函数的操作包括
Reflect.preventExtensionsObject.preventExtensions
getOwnPropertyDescriptor()
获取对象属性的属性描述符时,这个方法会调用。
有两个参数
obj源对象propertyKey需要获取属性描述符的属性名
返回值必须为一个对象或者undefined
1 | var proxy = new Proxy({ |
可以触发该函数的操作包括
Reflect.getOwnPropertyDescriptorObject.getOwnPropertyDescriptor
defineProperty()
在定义代理对象的属性时,这个方法会调用。
有三个参数
obj源对象propertyKey将设置的属性名descriptor将设置属性的属性描述符
返回值必须为一个boolean值或者可以转为boolean的值。
1 | var proxy = new Proxy({},{ |
可以触发该函数的操作包括
Reflect.definePropertyObject.definePropertyproxyObj.propertyKey = value
has()
在检查属性是否存在对象中时,这个方法会调用。
有两个参数
obj源对象propertyKey需要检查的属性名
返回值必须为一个boolean值或者可以转为boolean的值。
1 | var proxy = new Proxy({},{ |
可以触发该函数的操作包括
propertyKey in proxypropertyKey in Object.create(proxy)Reflect.haswith操作
get()
在读取代理对象属性时,这个方法会调用。
有三个参数
obj源对象propertyKey要获取的属性名context要绑定到getter的上下文,默认为调用对象本身。
返回值可以为任何值。
1 | var proxy = new Proxy({},{ |
可以触发该函数的操作包括
proxy[propertyKey]或者proxy.propertyKeyObject.create(proxy)[propertyKey]或者Object.create(proxy).propertyKeyReflect.get
set()
在设置代理对象属性值时,这个方法会调用。
有四个参数
obj源对象propertyKey设置的属性名value设置的属性值context要绑定到setter的上下文,默认为调用对象本身。
TIPS:
对于get和set,其中context参数的传入通常是proxy对象本身,但是对于处于原型链上的proxy,传入的就不是proxy对象了,而是触发操作的那个对象,比如,obj.propertykey = value,obj不是代理对象,但是obj的原型链上存在代理对象proxy,那传入context参数的就是obj而不是proxy了。而对于通过Reflect.set操作触发,context参数就跟set函数指定的一样了。
返回值必须为一个boolean值或者可以转为boolean的值。
1 | var proxy = new Proxy({},{ |
可以触发该函数的操作包括
proxy[propertyKey] = value或者proxy.propertyKey = valueObject.create(proxy)[propertyKey] = value或者Object.create(proxy).propertyKey = valueReflect.set
deteleProperty()
在删除对象的属性时,这个方法会调用
有两个参数
obj源对象propertyKey将删除的属性名
返回值必须为一个boolean值或者可以转为boolean的值。
1 | var proxy = new Proxy({},{ |
可以触发该函数的操作包括
delete proxy[propertyKey]或者delete proxy.propertyKeyReflect.deleteProperty
ownKeys()
获取代理对象属性名组成的数组时,这个方法会调用
有一个参数
obj源对象
返回值必须为一个可枚举的对象。
1 | var proxy = new Proxy({},{ |
可以触发该函数的操作包括
Object.getOwnPropertyNamesObject.getOwnPropertySymbolsReflect.ownKeysObject.keys
apply()
在对代理对象进行函数调用时,这个方法会调用
有一个参数
fn源函数context执行函数的上下文args参数的数组
返回值可以为任意值。
1 | function fn(msg){ |
可以触发该函数的操作包括
proxy(arg1,arg2,...,argN)Function.prototype.apply或者Function.prototype.callReflect.apply
construct()
以代理对象为构造器或者原型上存在代理对象的构造器生成对象时,这个方法会调用
有三个参数
obj源对象(可以被new)args参数数组newTarget被调用的构造函数
返回值必须为一个对象
1 | function fn(name){ |
可以触发该函数的操作包括
new proxy(arg1,arg2,...,argN)Reflect.construct
后记
学完感觉我能看懂vue3源码了。