前言
最近表妹毕业了,想成为一名前端开发攻城狮。在找工作的过程中,经常被面试官问到以下问题:
- 说下
Vue响应式原理? - 说下
Vue2中为什么需要$set? - 说下
Vue3中还有没有$set? - ....
表妹直接懵了,没研究过啊。为了刚毕业的表妹,和明年毕业的表弟不再被面试官虐,我打算讲一下这个问题。
本文将从以下几个角度,解读Vue响应式原理
- Vue2响应式原理
- Vue3响应式原理
- Vue2和Vue3原理区别
- 响应式拐弯抹角的响应式面试题
读完这篇文章,你应该能清楚的给面试官讲解Vue响应式原理,以及游刃有余的应对各种关于响应式的变种问题。
友情提示:本文代码,是丐版示意代码,是伪代码。主要是为了帮助理解Vue在其中是如何劫持数据,转变为响应式数据的。 Vue的源码实际复杂的多.
前置知识
在往下阅读前,我们需要解释几个名词,如果你都没听过,把鼠标移到屏幕右上角,那里有个X,用力点一下~
数据:后面都指组件中用data函数声明的数据。
响应式:即数据驱动视图。大白话:数据变化,界面自动变化。
依赖收集:当html标签中,使用到了数据,如插值表达式{{ xxx }},Vue会把这个标签保存起来。目的,是追踪这个标签,将来数据 xxx 变化时,更新该标签的内容。 把使用到数据的标签保存起来,这个动作,就叫依赖收集。
Vue2响应式原理
Vue2中,通过Object.defineProperty()方法对data函数声明的数据,进行了劫持(改造)。
我们已经知道什么是响应式:自动将变化后的最新值,更新到使用数据的标签上。 那Vue是如何做到的呢?关键点在于Object.defineProperty()方法,它可以对对象的属性,实现更加精准的控制。
接下来,我们用示例代码,来辅助理解。举个例子🙋♀️
现在每次访问data中的属性,都会触发get,每次修改data的属性,都会触发set。
看到这里,可能表妹更懵逼了,这玩意有什么用? 💥💥注意,此时要放大招了。此刻,你应该意识到每次访问data中的数据,都会出触发get。回想你在Vue中是如何使用数据的
那当数据变化时,Vue已知要去更新哪个dom元素,那Vue会在什么时候更新dom? 当然是越快越好。此时,set函数就有用武之地了:
🎉🎉此时,我们已经有了一个丐版响应式效果,让我用表妹最喜欢的看图说话,总结一下Vue2响应式原理
Vue2中$set的作用和原理?
面试官问完Vue2的响应式与原理后,经常会接一个问题,$set的作用和原理?
这其实还是在考察Vue2的响应式原理。
注意:💥💥在上一小节的看图说话中,看看defineProperty劫持data的属性,是发生在哪个阶段?
没错,是在创建阶段。而且是通过遍历对象的方式。创建阶段后,动态添加的新属性,是没有经过defineProperty劫持的,因此新增的属性,是没有响应式效果的。
但是,有时Vue的用户又真的需要,后动态添加的数据,也要有响应式效果。因此Vue提供了一个delete。 这两个方法,delete用来删除响应式属性,并且删除收集的依赖。
$set小结
作用:给响应式对象,添加新属性,并确保新属性也是响应式的。
原理:
- 通过检查目标对象是否是响应式的,如果不是则将其转换为响应式对象。
- 再调用Object.defineProperty,来劫持新添加的属性。
这样可以保证新添加的属性,能够实现数据驱动视图,实现响应式。
Vue3的响应式原理
不变的是:还是要对对象的属性,进行劫持。
变化的是:舍弃了defineProperty劫持对象属性,而使用ES6新增语法特性Proxy,劫持对象。
Proxy是ES6中的一个特性,它可以创建一个代理对象,用于拦截和自定义目标对象的操作。它同样可以实现get、set来对对象属性操作拦截。举个例子🙋♀️,感受一下
Vue3与Vue2响应式原理区别
表妹表示,差别不大啊,为啥要换Proxy,让面试官难住我🤬?
其实,差别大了, 对比两种劫持方式:
Vue2的劫持,是通过遍历的方式,对每个属性调用defineProperty逐个劫持,不包括后添加的属性。
Vue3的劫持,是通过Proxy,对所有属性全部劫持,包括后添加的属性。
让我再举最后一个例子🙋♀️🙋♀️:
Vue3的响应式,像是事件委托,不必给每个子元素,全部添加事件。通过事件冒泡,所有子元素的事件,都能被监听到,包括动态创建的子元素。
在Vue3的响应式中,不必再去遍历对象的所有属性,逐个劫持。因此,Vue3的性能要远远高于Vue2,并且Vue3中移除掉了$set方法。
另外,Proxy除了get和set,其实还有deletePropery可以劫持对象删除属性的操作,$delete在Vue3中也移除掉了。
总结
面试官问:说下Vue2的响应式原理?
- Vue2中在创建阶段,会遍历data函数声明的对象。
- 调用defineProperty,为每个属性添加
get和set方法。 - 其中,get用来
收集依赖,追踪使用数据的dom,确保将来去更新dom - 其中,set用来
通知依赖(dom)更新界面内容。 - 从而实现了,响应式效果。
面试官问:说下Vue3的响应式原理?
- 与Vue2大致相同,还是
get收集依赖,set通知依赖更新. - 区别在于,Vue3使用Proxy替代了defineProperty实现
get和set
什么?面试官你问为什么要用Proxy?
事件委托,面试官你晓得吧? Proxy类似事件委托:
- 不必遍历对象,逐个添加劫持
- 动态添加的属性,依然会自动劫持,依然有响应式效果