1、Vue2响应式原理:
在此之前我们先简单的了解一下什么是MVVM:
MVVM虽然是4个字母但是其实是由三个部分组成:Model,View和ViewModel。与MVC相比他是视图模型双向绑定,也就是多的那个viewModel。
M V VM 解释 Model 代表数据模型(Vue的data),数据和业务逻辑都在Model层中定义; View 代表UI视图,负责数据的展示(Vue的el); ViewModel 是一个对象,负责监听 Model 中数据的改变并且控制View视图的更新,处理用户交互操作;
- Model 和 View 并无直接关联,而是通过 ViewModel 来进行交互的(即双向数据绑定),
- Model 和 ViewModel之间有着双向数据绑定的联系。 View的变化可以引起Model的变化,Model的变化也可以引起View变化(类似于浅拷贝)。
ViewModel
是View
和Model
层的桥梁,数据会绑定到viewModel
层并自动将数据渲染到页面中,视图变化的时候会通知viewModel
层更新数据。
-
如何实现的?
Vue2响应式原理上采用的数据劫持配合发布者-订阅者的模式的方式
- 对于对象,使用Object.defineProperty() 对数据进行读取拦截等操作,也就是常说的劫持各个属性的getter和setter,当数据更新后发布消息给订阅者,触发相应的监听回调后触发视图更新,这里是MVVM的绑定原理
- 对于数组,是通过重写更新数组的一系列方法(slice、replace、push、shift、split、filter等等)来实现拦截,其实他本质上就是把原来js,es6等对数组这些进行操作的函数进行了一个包裹,当你使用他包裹的函数对数组进行操作后他就能帮你更新视图从而实现响应式的目的
-
存在的问题:
-
从中我们可以看出vue2对响应式的处理好像有那么一点的“粗暴”
显然,这样子会存在某些问题
-
问题1: 例如上面我说的,对于数组,是通过包裹一些函数,那么如果我使用没有被他包裹的函数那么答案很显然,我们的界面是不会更新,不仅如此,如果我们直接对数组的下标进行修改,也不可以
> 即:
> > ``` > let arr=["dad","what","me"]; > arr=arr.filter((str)=>{ > return str==='dad' > }) > console.log(arr); > //filter是被vue2包裹的方法,这里过滤掉了what和me,那么界面上呈现的就会更新只剩dad。 > //而如果通过下标如: > arr[1]=''//这样子进行修改,那么界面不会更新 > ``` > > - **问题2:** 如果我们对对象直接进行增删属性的操作,界面不会更新,必须得通过this.$set()来新增,删除用this.$delete
-
2、Vue3响应式又是如何做的呢?
首先,既然,vue3是对于vue2的更高版本,那么对于vue2存在的问题必然是要解决的,像上述存在的两个问题点,在vue3中都得以解决,这依赖于我们的reactive(), 把数组对象什么的给塞里面,全都变成了响应式的,并且他还是深层次,非常的好用,非常的神奇,当你对reactive里的对象用console.log去看的时候你会发现,在前面他们有Proxy这个单词
-
没错,主要就是通过proxy(代理)和reflect
proxy代理是ES6新出的功能,当你对他代理的目标对象进行修改和查探等操作时,他都知道。
Proxy
接受两个参数:
第一个参数是所要代理的目标对象(上例是一个
data
对象),即如果没有Proxy
的介入,操作原来要访问的就是这个data
对象。这里的对象是指对象类型(数组也是对象类型)。第二个参数是一个配置对象
handler
,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作。比如,上面代码中,配置对象有一个get
方法,用来拦截对目标对象属性的访问请求。get
方法的两个参数分别是目标对象和所要访问的属性。2.
Reflect
也是ES6新增的API。Reflect
对象和Proxy
对象一样也是用来操作对象的,但是Reflect
对象的设计目的有重大的意义。
Reflect
是一个内置的对象,它提供拦截 JavaScript 操作的方法。Reflect不是一个函数对象,因此它是不可构造的。Reflect
的所有的方法都是静态的就和Math
一样,目前它还没有静态属性