Proxy 和 Object.defineProperty
· 分享镜#h5
Proxy
定义
Proxy主要用于改变对象属性的默认访问行为,在目标对象之前架设一层"拦截",外界对该属性的访问,都需先通过这一层拦截,因此提供了一层机制,可对外界的访问进行过滤和改写。
用法:
/*
* target: 目标对象
* handler: 配置对象,用来定义拦截的行为
* oproxy: Proxy构造器的实例
*/
const obj = {}
const handler = {
get(target, key,receiver){ // 拦截对象属性的读取
console.log('get')
return Reflect.get(target, key,receiver)
},
set(target, key, value, receiver){ // 拦截对象属性的设置
console.log('set')
return Reflect.set(target, key, value, receiver)
},
has(target, key){ // 拦截propKey in proxy 操作
console.log('has')
return Reflect.has(target, key)
},
deleteProperty(target, key){// 拦截delete proxy[propKey] 操作 返回一个布尔值
console.log('deleteProperty')
return Reflect.deleteProperty(target, key)
},
defineProperty(target, key, desc){ // 拦截Object.defineProperty(proxy, key, desc)/Object.defineProperties(proxy,decs) 返回一个布尔值
return Reflect.defineProperty(target, key,desc)
},
construct(target, args){ // 拦截 proxy实例作为构造函数实例化的操作,比如 new proxy(...args)
console.log('construct')
return Reflect.construct(target, args)
},
ownKeys(target){ //getOwnPropertyNames(proxy) / getOwnPropertySymbols(proxy)/for...in/Object.keys(proxy),返回一个数组。Object.keys,而Object.keys()返回结果仅包括目标对象可遍历的属性
console.log('ownKeys')
return Reflect.ownKeys(target)
},
getOwnPropertyDescriptor(target,key){//拦截Object.getOwnPropertyDescriptor(), 返回属性的的描述对象
console.log('getOwnPropertyDescriptor')
return Reflect.getOwnPropertyDescriptor(target,key)
},
preventExtensions(target){ // 拦截Object.preventExtensions(proxy), 返回一个布尔值
console.log('preventExtensions')
return Reflect.preventExtensions(target)
},
getPrototypeOf(target){ // 拦截Object.getPrototyOf(proxy), 返回一个对象
console.log('getPrototypeOf')
return Reflect.getPrototypeOf(target)
},
setPrototypeOf(target, proto){// 拦截Object.setPrototyOf(proxy,proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
console.log('setPrototypeOf')
return Reflect.setPrototypeOf(target, proto)
},
apply(target,object ,args){//拦截proxy实例作为函数时的调用,比如proxy(...args)/proxy.call(object, ...args)/proxy.apply(...args)
console.log('apply')
return Reflect.apply(target, object ,args)
},
isExtensible(target){// 拦截Object.isExtensible(), 返回一个布尔值
console.log('isExtensible')
return Reflect.isExtensible(target)
}
}
const oproxy = new Proxy(obj, handler)
obj.a = 1
console.log(oproxy.a)//
Proxy代理的对象属性是外层的,如果需要属性值对象进行代理,可以通过递归设置代理。
设置内层属性递归代理
const obj = {
a: 1,
objb: {
c: 2
}
}
const handler = {
get(target, key, receiver){
console.log('get')
const value = target[key]
if(value !== 'null' && typeof value === 'object'){
return new Proxy(value, handler)
}
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver){
return Reflect.set(target, key, value, receiver)
}
}
const oproxy = new Proxy(obj, handler)
oproxy.objb.c
// 输出
// get
// get
// 2
Object.defineProperty
定义
Object.defineProperty()直接在对象定义新属性,或者修改对象上的现有属性,并返回该对象。
用法:
/*
* obj 要在其上定义或修改属性的对象
* prop 要定义或修改的属性的名称或者Symbol
* descriptor 定义或修改的属性描述符
*/
Object.defineProperty(obj, prop, descriptor)
描述符: 分为数据描述符和存取描述符,一个描述符只能是其中的一个,不能同时是两者。
- 数据描述符:有值的属性,该值是否可重写。
- 存取描述符:由getter 和setter函数所描述的属性。
共享属性: 1、configurable 表示可配置的,默认为false。当为true时,该属性的描述符才可以被改变,同时该属性可以被删除。
2、enumrable 表示可枚举的,默认为false。当为true时,该属性才会在对象枚举时枚举到。
数据描述符特有属性: 1、value 表示属性对应的值,默认为undefined 2、writable 表示属性是否可修改的,默认为false。只有值为true时,属性的值才可以被修改运算符修改成功。
const obj = {}
Object.defineProperty(obj, 'name', {
configurable: true,
enumrable: true,
value: 'jack',
writable: true
})
存取描述符特有属性: **1、get ** 当获取属性值的时候就会执行getter函数,该函数返回一个值, 默认为undefined 2、set 当设置属性值的时候就会执行setter函数
const obj = {}
Object.defineProperty(obj, 'name',{
configurable: true,
enumrable: true,
get(){
console.log('get--name')
return 'jack'
},
set(value){
console.log('set---name')
return value
}
})
Proxy和Object.defineProperty 对比:
- Proxy是对整个对象的代理,而Object.defineProperty是代理对象的单个属性。
- 对象上新增属性,Proxy可以监听到,而Object.defineProperty不可以
- 数组新增修改,Proxy可以监听到,而Object.defineProperty不可以
- 若对象内部的所有属性均要递归监听,Proxy可以只在调用的时候监听,而Object.defineProperty需要一次全部实现监听,性能比Proxy差
- Proxy不兼容ie, Object.defineProperty不兼容ie8以下
- Proxy使用上比Object.defineProperty更方便
评论(0)
登录后参与评论。
还没有评论,来抢沙发吧。

