Proxy与Reflect
新建一个代理对象,通过操作代理对象就能操作原对象。Proxy构造函数的两个参数,一个是需要劫持的对象,一个是操作函数对象。如果不设置操作函数对象,则默认使用Reflect的相关API,也就是说Reflect提供了proxy13种操作函数的默认实现。
const person = {
name:'lf',
age: 19
}
const p = new Proxy(person, {
get(target, property){
return Reflect.get(target, property)
},
set(target, property, value){
target[property] = value
}
})
console.log(p.name) // 'lf'
p.age=23
console.log(p.age) // 23
console.log(person.age) // 23
常用的proxy劫持操作函数以下几个:
- get(target, propKey, receiver):拦截对象属性的读取,比如
proxy.foo
和proxy['foo']
。 - set(target, propKey, value, receiver):拦截对象属性的设置,比如
proxy.foo = v
或proxy['foo'] = v
,返回一个布尔值。 - has(target, propKey):拦截
propKey in proxy
的操作,返回一个布尔值。 - deleteProperty(target, propKey):拦截
delete proxy[propKey]
的操作,返回一个布尔值。 - ownKeys(target):拦截
Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()
的返回结果仅包括目标对象自身的可遍历属性。 - defineProperty(target, propKey, propDesc):拦截
Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一个布尔值。 - getPrototypeOf(target):拦截
Object.getPrototypeOf(proxy)
,返回一个对象。 - apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如
proxy(...args)
、proxy.call(object, ...args)
、proxy.apply(...)
。
对应的Reflect方法:
- Reflect.apply(target, thisArg, args)
- Reflect.get(target, name, receiver) in
- Reflect.set(target, name, value, receiver)
- Reflect.defineProperty(target, name, desc)
- Reflect.deleteProperty(target, name) delete
- Reflect.has(target, name)
- Reflect.ownKeys(target) Object.keys()
- Reflect.getPrototypeOf(target)
Reflect的作用:
原来判断一个对象是否有某属性 in 现在可以用Reflect.has(target, 'name') 注意对象属性得是字符串
原来删除某属性 delete 现在可以用Reflect.deleteProperty(target, 'name')
原来获取一个对象的所有属性 Object.keys() 现在可以用Reflect.ownKeys(target)
综上,其他的功能请自行使用。Reflect提供了统一的一套操作对象的API
vue3.0与2.0 Object.defineProperty的对比
vue2.0使用Object.defineProperty(target, prop, handler)来劫持对象属性的相关操作
- 只能劫持对象属性,需要遍历对象的所有属性
- 无法检测到对象属性的添加,vue实例初始化后新添加的对象属性不具备响应式
- Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应,也无法监听到push等方法,vue中重写了这些方法来增加setter
3.0 使用es6 proxy来监听数据的变化
- 可以劫持整个对象
- 对象新增属性可以实时响应式,可以检测到数组下标的变化
- 因为Proxy是ES6新增的属性,有些浏览器还不支持,只能兼容到IE11