Vue响应式Object.defineProperty与Proxy

Object.defineProperty用法

Object.defineProperty()静态方法会直接在一个对象上定义一个新属性,或修改其现有属性,并返回此对象。

Object.defineProperty(obj, prop, descriptor)
参数:
obj:要定义属性的对象。
prop:一个字符串或 Symbol,指定了要定义或修改的属性键。
descriptor:要定义或修改的属性的描述符。

对象新增或者修改属性
let obj = {}
Object.defineProperty(obj, 'sex', {
    value: 42
});
console.log(obj)
进行对象读取或写入值时的监听
let obj = {}
Object.defineProperty(obj, 'sex', {
   get: function(val) {  //访问对象属性时,触发get方法
    console.log(obj)
    obj.sex=2
    return val
  },
  set: function(newVal) { //修改对象属性时,触发set方法
    console.log('set:'+ newVal)
  }
});
console.log(obj.sex)//访问对象属性
监听对象上的多个属性

监听对象需要,通过遍历对象的属性名进行Object.defineProperty绑定,从而实现对象属性的监听。

let obj = {
    name: '',
    sex: 0
}
// 实现一个响应式函数
function defineProperty(obj, key, val) {
    Object.defineProperty(obj, key, {
        get(val) {
            console.log(`访问了${key}属性`)
            return val
        },
        set(newVal) {
            console.log(`${key}属性被修改为${newVal}了`)
            val = newVal
        }
    })
}
// 实现一个遍历函数Observer
function Observer(obj) {
    Object.keys(obj).forEach((key) => {
        defineProperty(obj, key, obj[key])
    })
}
Observer(obj)
console.log(obj.age)
obj.age = 18
console.log(obj.age)

Proxy用法

Proxy是Es6的一个语法,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。new Proxy(target, handler)

var person = {
  name: "张三"
};
var proxy = new Proxy(person, {
  get: function(target, propKey) {
     console.log(propKey+":"+target.name)//name:张三
  },
set: function(obj, propKey, value) {
     console.log(obj)//person的对象
     console.log(propKey)//对象属性名
      console.log(value)//对象属性值
}
});
proxy.name // "张三"
proxy.name ="小明"
proxy.sex="man"

proxy实现监听数据变化,传入目标target对象,不需要通过遍历属性就可以监听对象的变化。

Vue3响应式抛弃Object.defineProperty的原因

1.一次只能对一个属性进行监听,需要遍历来对所有属性监听。

  1. 在遇到一个对象的属性还是一个对象的情况下,需要递归监听。
  2. 对于对象的新增属性,需要手动监听
  3. 对于数组通过push、unshift方法增加的元素,也无法监听
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容