【Vue 响应式数据原理】数据双向绑定原理

2023-03-25 12:37:31 浏览数 (1)

1. vue 2 响应式原理

Vue 数据双向绑定时通过数据劫持 结合 订阅者-发布者模式 来实现的(观察者模式)。

  • 数据劫持: 通过 Object.defineProperty(obj, key, value)方法给对象的每一个属性都加上一个 gettersetter(监听的是每一个属性)。
  • 订阅者-发布者: 当我们修改某个属性的值时,底层调用了 setter修改数据,当数据发生变化会被vue实例监听到,从而调用相应的getter方法,获取新数据,实现数据双向绑定。
  • 再通过deff算法将数据更新到页面。(多说一句,react是单向数据绑定,就只是通过deff算法将数据更新到页面)

1.1 对象数据响应式原理

  • 通过Object.defineProperty(obj, key, value)来监听已有的数据,当数据发生变化会调用响应的settergetter
  • Object.defineProperty()针对的是对象的某个属性,而且这个操作在vue的初始化阶段就完成了,所以新增和删除的属性无法监听,通过Vue.set(obj, newkey, newvalue)Vue.delete(obj, key)方法来解决,通过set()和delete()方法新增对象就相当于初始化阶段的数据响应式处理。

1.2 数组数据响应式原理

vue 对JavaScript数组的方法进行了二次封装(重写)来劫持这些方法,在原有操作数据的基础上,添加了将数据响应到页面的功能。

缺点:

  • 新增、删除 数组里的数据,不会引起页面变化。
  • 通过索引修改数据,不会引起页面变化。
  • 因为getter和setter只能监听到数据的访问和修改动作,删除和添加动作无法监听到。

为什么监听不到呢?

  • Vue 出于对性能的考虑,数组没有使用Object.defineProperty对属性添加settergetter
  • bject.defineProperty()是可以对数组实现监听操作的,但是vue并没有实现这个功能,因为数组长度不定而且数据可能会很多,如果对每一个数据都实现监听,性能代价太大。

但是注意:数组中的元素是引用类型时是会被监听的

解决方案:

  • 添加数据:this.$set(obj, newkey, newvalue)Vue.set(obj, newkey, newvalue)
  • 删除数据:this.$delete(obj, key) 或 Vue.delete(obj, key)
    • this.$delete:只是被删除的数组成员变为 empty或undefined,其他元素的键值不变
    • Vue.delete:直接删除了数组的成员,并且改变了数组的键值(对象是响应式的,确保删除能触发更新视图,这个方法主要用于避开 Vue 不能监听到属性被删除的限制)

2. Vue 3 响应式原理

2.1 vue 2 缺陷

vue 2 通过设定对象属性getter/setter方法来监听数据的变化,同时getter也用于依赖收集,而setter在数据变更时通知订阅者更新视图。

2.2 新的代理方式 Proxy

Proxy,字面意思是代理,是ES6提供的一个新的API,用于修改某些操作的默认行为,可以理解为在目标对象之前做一层拦截,外部所有的访问都必须通过这层拦截,通过这层拦截可以做很多事情,比如对数据进行过滤、修改或者收集信息之类。

所以只需一层代理就可以监听统计结构下所有属性变化,包括新增和删除属性。

  • Proxy直接代理整个对象而非对象属性:
    • Proxy的代理针对的是整个对象,而不是像Object.defineProperty针对某个属性。只需做一层代理就可以监听同级结构下的所有属性变化,包括新增属性和删除属性
  • Proxy也可以监听数组的变化。

0 人点赞