【知识体系 - Vue】Vue2.x的数据响应式

115 阅读1分钟

Vue2.x的数据响应式

图解

vue2.x数据响应式.jpeg

vue2.x数据响应式.png

浅层分析

总体

  • 数据劫持 + 依赖收集(发布订阅者模式)

过程

  • vue初始化实例时,遍历data中的所有属性并通过Object.defineProperty重新定义属性。(把属性都转化为getter、setter)
  • 获取属性时,调用getter。通知Dep.depend()进行依赖收集,watcher存储收集的结果
  • 更新数据时,调用setter。通知Dep.notify()进行委托派发,遍历通知依赖的所有watcher更新
  • wacther触发re-render()进行组件重新渲染

深层分析

  • Observer(将 普通对象 转化为 响应式对象)

    • 执行 object.defineProperty() 进行数据劫持
    • 将data中的属性转化成带有getter、setter方法的响应式对象
    针对对象的类型做了不同的处理
    1. 深层嵌套的对象数据 -- 递归遍历
    2. 数组 -- 重写数组的7个方法 push/pop/shift/unshift/reverse/sort/splice
    
  • Dep(监听响应式对象数据的变化)

    • 监听对象的getter、setter
      • getter -> dep.depend()【依赖收集】
      • setter -> dep.notify() 【派发委托】
  • Watcher(存储Dep的结果)

    • Dep.depend()/Dep.notify()结果存入watcher中
  • Scheduler(watcher的调度器)

    • 对watcher的调度,将其放入队列中 通过事件循环 管理执行

使用JS实现Object.defineProperty

let obj = {}
let value = '你好'
Object.defineProperty(obj, "key",{
  get:function() {
    console.log('获取数据')
    return value
  },
  set:function(newValue) {
    console.log('更新数据');
    value = newValue
  }
})

console.log(obj.key);
obj.key = '我很好'
console.log(obj.key);

监听式


let obj = {
  name: 'elio',
  age: 26,
  address: {
    country: 'china',
    province: 'sz'
  }
}

function observer(obj) {
  if (typeof obj !== 'object' || obj == null) return
  for (const key in obj) {
    // 给对象每一项都设置响应式
    defineProperty(obj, key, obj[key])
  }
}

function defineProperty(obj ,key ,value) {
  // 嵌套对象的处理,遍历
  observer(value)
  Object.defineProperty(obj, key,{
    get:function() {
      console.log(`读取${key}成功`)
      return value
    },
    set:function(newValue) {
      if (newValue === value) return
      // 3.针对对象的设置
      observer(value)
      console.log(`监听设置成功,${newValue}`);
      value = newValue
    }
  })
}

// 执行监听
observer(obj)

// obj.age = 18 // 监听设置成功,18

// obj.address.country = 'USA' 
/**
  读取address成功
  监听设置成功,USA
 */

// 3
obj.address = {
  email: '123@163.com'
}
obj.address.email = 'asdasd'