# 基于数据劫持双向绑定
- 利用
Proxy或Object.defineProperty生成的Observer对对象、对象属性进行劫持,在属性变化后通知订阅者Watcher - 解析器
Compiler解析模板中的指令,收集指令需要的数据和方法,等待数据变化时重新渲染 Watcher连接Observer和Watcher,接收Observer产生的数据变化,并根据Compiler提供的指令进行视图渲染,促使视图变化
Vue 3开始使用Proxy实现双向绑定,因为Object.defineProperty有如下缺点:
- 不能实现数组和对象的部分监听情况。无法监听数组下标的变化,导致Vue实现数组变异方法来解决问题。无法监听属性的新增删除操作,需要
Vue.set。 - 需要遍历所有的属性,如果 vue 对象的 
data/computed/props数据多,遍历自然会慢很多。 那么Object.defineProperty需要监听所有的属性的变化,占用内存相应就大了。 
Proxy直接拦截/代理对象,不需深度遍历属性,而且支持监听数组变化。
# computed工作流程
export default {
  data() {
    return {
      message: ''
    }
  },
  computed: {
    reversedMessage() {
      return this.message.split('').reverse().join('')
    }
  }
}
 1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
data属性初始化gettersettercomputed计算属性初始化,提供的函数将用作属性vm.reversedMessage的getter- 当首次获取 
reversedMessage计算属性的值时,Dep开始依赖收集 - 在执行 
messagegetter方法时,如果Dep处于依赖收集状态,则判定message为reversedMessage的依赖,并建立依赖关系 - 当 
message发生变化时,根据依赖关系,触发reversedMessage的重新计算 
# watch原理
watch 监听实现利用遍历获取属性,触发“数据劫持get”逐个收集依赖,这样做的好处是其上级的属性发生修改也能执行回调。
与 data 和 computed 不同,watch 收集依赖的流程是发生在页面渲染之前,而前两者是在页面渲染时进行取值才会收集依赖。
computed 和 watch 的异同:
computed要依赖data上的属性变化返回一个值,watch 则是观察数据触发回调;computed和watch依赖收集的发生点不同;computed的更新需要“渲染Watcher”的辅助,watch 不需要。