vue2 双向数据绑定和数据响应式

·  阅读 682

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

前言:

对于 vue 的双向数据绑定和数据响应式本人最近花了一些时间去深究,自认为算是理清了它们之间的关系和主要的实现原理

双向数据绑定和数据响应式

双向数据绑定就是视图层或者数据层中的一方发生变化,相对应的另一层也会发生变化。数据响应式就是拦截数据的访问与更新,在其发生这些操作的时候可以让我们知晓。所以,数据响应式是用来服务双向数据绑定的。

数据响应式的思想基本原理

思想

我们都知道 vue2 通过 Object.defineProperty 来实现数据拦截,具体是实现方法就是在这个方法基础上在添加亿点点细节。 为了便于功能区分,先定义两个方法(observe、defineReactive)和一个类(Observer)。它们的功能分别是 observe 为最外层响应式方法,用于对要进行响应式的数据做简单过滤,对于基础类型的数据直接返回原值,对于引用类型的数据(如对象和数组)将其变为 Observer 实例;Observe 实例中通过定义对应处理对象和数组的方法,来管理数据的响应式进程;defineReactive 方法是最终进行数据拦截的地方,对传入的数据也进行响应式处理即调用 observe 方法,这样就形成了一个递归操作,但是这个递归不会死循环,应该在 observe 方法中对于基础类型的数据会直接返回原值。在这里进行拦截数据时,get 中就直接返回该值的数据,set 中就将传入的新值赋值给该数据项,当然此处做一下数据判断,看新值是否和原值一样,如果一样的话就不进行赋值操作。

对象和数组处理的差异

以上的流程对于对象数据是完全OK的,但是对于数组的话就会有问题,因为对于对象数据,其数据变化主要为值的变化,基本上都是通过赋值操作完成,但是对于数组,其除了通过赋值操作实现数组项的数据变化外,还可以通过方法实现对数组数据的变化,故需要对数组做一些特定的操作即来拦截数组的这些方法。此时就需要一个管理这些数组操作方法的单一文件 array.js 和一个定义一个对象属性的方法 def。在 array.js 中主要拦截的数组方法为 push、pop、shift、unshift、splice、reverse、sort,对于这些方法不需要完全重写,只用在使用它们的时候走一边我们自定义的操作实现数据拦截后在让它们按原来的操作继续即可。具体实现如下,先获取 Array.prototype,再通过 def 方法修改原型上的这些方法,对于push、unshift、splice因为能插入新项,故通过 observe 方法劫持(侦测)这些数据(插入新项)。最后在 Observer 类中通过 Object.setPrototypeOf 让数组的原型变为 array.js 中重写的数组原型即可。

数据双向绑定

在 Vue 中通过 Dep 和 Watcher 实现依赖收集和更新通知。故此时需创建两个类 Dep 和 Watcher,Dep类专门帮助我们管理依赖,可以收集依赖,删除依赖,向依赖发送通知等;Watcher是一个中间的角色,数据发生变化时通知它,然后它再通知其他地方。核心思想为数据使用时收集依赖,数据更新时,通知更新

参考

【尚硅谷】Vue源码解析之数据响应式原理
通俗易懂了解Vue双向绑定原理及实现

个人优化

尚硅谷课程中,存在一定问题:
1,就是添加 watcher 时,会触发多次依赖收集,但并未做重复依赖处理,故我在 Dep 的 depend 方法上加上是否存在的判断,条件判断 Dep.target ---> Dep.target && !this.subs.includes(Dep.target);
2,我不理解为什么要单独对子元素进行额外依赖收集,我个人认为在对子元素进行响应式处理后就会为其进行依赖收集。
以上就是我整理的代码中会与尚硅谷课程有出入的地方,若有什么建议和意见,望提出!

代码在这里(注,my_data_reactive 这个文件夹中就是尚硅谷课程中的代码,该代码是他人整理,本代码的原仓库在这里)

分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改