实现数据绑定的做法有大致如下几种:

  • 发布者-订阅者模式(backbone.js)
  • 脏值检查(angular.js)
  • 数据劫持(vue.js)

数据劫持双向绑定

vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

数据劫持是双向绑定各种方案中比较流行的一种,最著名的实现就是Vue。

基于数据劫持的双向绑定离不开Proxy与Object.defineProperty等方法对对象/对象属性的"劫持",我们要实现一个完整的双向绑定需要以下几个要点。

  • 利用Proxy或Object.defineProperty生成的Observer针对对象/对象的属性进行"劫持",在属性发生变化后通知订阅者
  • 解析器Compile解析模板中的Directive(指令),收集指令所依赖的方法和数据,等待数据变化然后进行渲染
  • Watcher属于Observer和Compile桥梁,它将接收到的Observer产生的数据变化,并根据Compile提供的指令进行视图渲染,使得数据变化促使视图变化

基于 Object.defineProperty 双向绑定

Vue 数据劫持双向绑定
在Vue实例初始化时会进行 data 的初始化操作,其中会调用 observe 方法并生成一个Observer 监听者对象,在 new Observer 时,即 Observer 的构造函数中会对 data 下的所有属性对象进行监听(递归,直到 !value || typeof value !== 'object' -》 return; ),那么针对每一个属性都会持有自己的一个 Dep 实例(消息管理员)用于存储订阅者。

a 属性被属性 b 依赖时(即调用了 aget ),调用 dep.depend(); 方法将 Watcher (订阅者)添加到 dep 中的 subs 数组中存储,同时该订阅者同时持有该 depiddepIds 中(由于 b 可以同时依赖于多个 datadepIds 为数组)。

this.a = 'new value'; 时,set 方法被触发,并调用 dep.notify(); 通知订阅者更新。

Object.defineProperty的缺陷

  1. 无法监听数组变化(Vue数组更新检测
  2. 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历,如果属性值也是对象那么需要深度遍历,显然能劫持一个完整的对象是更好的选择。

基于Proxy的双向绑定

Proxy可以直接监听对象而非属性
Proxy可以直接监听数组的变化

Proxy在ES2015规范中被正式发布,它在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写,我们可以这样认为,Proxy是Object.defineProperty的全方位加强版。

Proxy的其他优势

Proxy有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的。
Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改。
Proxy作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利。
当然,Proxy的劣势就是兼容性问题,而且无法用polyfill磨平,因此Vue的作者才声明需要等到下个大版本(3.0)才能用Proxy重写。

掘金:实现双向绑定Proxy比defineproperty优劣如何?

相关文章:

  • 2021-10-13
  • 2021-08-31
猜你喜欢
  • 2021-11-15
  • 2022-12-23
  • 2022-12-23
  • 2020-03-18
  • 2022-02-14
  • 2021-06-20
  • 2021-04-30
相关资源
相似解决方案