|

Aimee

Write the Code. Change the World.

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

登录后参与评论。

还没有评论,来抢沙发吧。

回到顶部