代理和反射

代理(Proxy)是一种可以拦截并改变底层JavaScript引擎操作的包装器。

ES6中数组被认为是奇异对象(exotic object)

调用new Proxy可创建目标(target)对象的代理,他虚拟化了目标,二者看起来功能一致。

代理可以拦截JavaScript引擎内部目标的底层对象操作,会触发对应的陷阱函数

反射APIReflect对象的形式出现,对象中方法的默认特性与相同的底层操作一直,代理可以覆写这些操作,每个代理陷阱都对应一个命名和参数相同的Reflect方法

代理陷阱覆写的特性默认特性
get读取一个属性值Reflect.get()
set写入一个属性值Reflect.set()
hasin操作符Reflect.has()
deletePropertydelete操作符Reflect.deleteProperty()
getPrototypeOfObject.getPrototypeOf()Reflect.getPrototypeOf()
setPrototypeOfObject.setPrototypeOf()Reflect.setPrototypeOf()
isExtensibleObject.isExtensible()Reflect.isExtensible()
preventExtensionsObject.preventExtensions()Reflect.preventExtensions()
getOwnPropertyDescriptorObject.getOwnPropertyDescriptor()Reflect.getOwnPropertyDescriptor()
definePropertyObject.defineProperty()Reflect.defineProperty()
ownKeysObject.keys()Object.getOwnPropertyNames()和、Object.getOwnPropertySymbols()Reflect.ownKeys()
apply调用一个函数Reflect.apply()
constructnew调用一个函数Reflect.construct()

代理的使用

1let target = {}
2let proxy = new Proxy(target, {
3    /**
4     * 
5     * @param {Object}          trapTarget  接受属性的被代理的目标对象,本例中的target
6     * @param {String, Symbol}  key         要写入的属性键值
7     * @param {*}               value       要写入的属性键值
8     * @param {Object}          receiver    代理对象,本例中的proxy
9     */
10    set(trapTarget, key, value, receiver) {
11        console.log(trapTarget === target, key, value, receiver === proxy); // true 'name' 'proxy' true
12        
13        return Reflect.set(trapTarget, key, value, receiver)
14    },
15    get(trapTarget, key, receiver){
16        if( !(key in receiver) ){
17            throw new Error(`属性 ${key} 不存在`)
18        }
19        
20        return Reflect.get(trapTarget, key, receiver)
21    }
22})
23
24proxy.name = "proxy"
25console.log(proxy.name) // "proxy"
26console.log(target.name) // "proxy"

浏览器支持程度

49以上版本Chrome支持ProxyIE浏览器不支持。