头图

Vue2实现响应式的核心:

  • 对象:通过defineProperty对对象的已有属性值的读取和修改进行劫持(监视/拦截)
  • 数组:通过重写数组更新数组一系列更新元素的方法来实现元素修改的劫持
let data = {
  name: 'Liane',
  age: 18
}
//模拟组件实例
let _this = {}

//Object.defaineProperty()用法
for(let item in data){
  Object.defineProperty(_this,item,{
    //每次获取属性时都会触发该属性的get()方法
    get(){
      return data[itme]
    },
    //每次修改属性值时,都会触发该属性的set()方法
    set(newValue){
      data[item] = newValue
    }
  })
}
console.log(_this.name)  //Liane
_this.name = 'Ann'
console.log(_this.name) //Ann

1、使用observe函数遍历data的每个属性

image.png
2、调用Object.defineProperty()对每个属性做响应式处理:利用拦截器属性get()和set()方法做订阅-发布处理。

image.png

3、当对一个属性进行响应式处理的适合,会实例化一个Dep实例,并将用到这个属性的组件所对应的Watcher实例全部存放在subs数组里,当属性被修改时,通知watcher,调用里面的render函数,进行dom的diff和更新。
image.png

问题:

  • 需要遍历需要监听的每个对象的每个属性,对其添加definePropert方法,通过其内部的get()和set()方法进行数据的监听和拦截,实现非常复杂。
  • 对象直接新添加的属性或删除已有属性,界面不会自动更新,需要使用Vue.set()
  • 直接通过下标替换元素或更新length,界面也不会自动更新
  • 数据的响应式处理和视图未完全解耦

Vue3实现响应式的核心:
通过proxy代理:拦截对data任意属性的任意操作,包括属性值的读写,属性的添加,属性的删除等。
通过reflect反射,动态对被代理对象的相应属性进行特定的操作。

//声明一个普通对象,让其变成一个proxy代理响应式对象
let user = {
  name: 'Liane',
  age: 18
}

//通过new运算符,实例化一个proxy对象,new Proxy(target, handler)
//参数1、target--目标对象
//参数2、handler--处理器对象,用来监视数据,及数据操作
let proxyUser = new Proxy(user, {
  //获取目标对象的某个属性值
  get(target, prop) {
    console.log('get方法调用了')
    //通过Reflect反射,对被代理对象(目标对象)的相应属性进行特定操作
    return Reflect.get(target, prop)
  },
  //修改目标对象的属性值/为目标对象添加新的属性
  set(target, prop, value) {
    console.log('set方法调用了')
    return Reflect.set(target, prop, value)
  },
  //删除目标对象上的某个属性值
  deleteProperty(target, prop) {
    console.log('delete方法调用了')
    return Reflect.deleteProperty(target, prop)
  }
})

console.log(proxyUser) //Proxy {name:"Liane",age:18}
//通过代理对象获取目标对象中的某个属性值
console.log(proxyUser.name) //Liane
//修改源对象的属性,代理对象的值也会修改
user.name = 'Ann'
console.log(proxyUser.name) //Ann
//通过代理对象,修改目标对象上的属性值
proxyUser.name = 'Rose'
console.log(user.name)  //Rose
//通过代理对象,删除目标对象上的属性值
delete proxyUser.name
console.log(user) //{age:18}
</script >

优点:

  • 在我们动态为data添加属性时,不需要做任何处理,这个属性就已经是响应式的了。(不用循环遍历data的每个属性,对属性都做一遍响应式处理,而是直接代理整个data对象)
  • 数组的任何操作也可以触发相应。

Liane
16 声望2 粉丝