「每日一题」抖音面试题:请阐述 vue 数据绑定的实现原理
vue 数据绑定的实现原理?
这个题目本身不是特别难,只能说是作为社招的基础面试题,但是如果想回答好这道题也不是很容易。
不信接着往下看
1、概括回答
vue.js 是一个非常优秀的前端开发框架,使用 vue 的版本是 v2.x
vue 几个核心的地方:vue 实例化,虚拟 DOM,模板编译过程,数据绑定。
我们开始回到正题,vue.js 的作者尤雨溪最初就是尝试实现一个类似 angular1 的东西,发现里面对于数据处理非常不优雅,于是创造性的尝试利用 ES5 中的 Object.defineProperty 来实现数据绑定,于是就有了最初的 vue。
vue 的数据绑定的实现原理离不开 vue 中响应式的数据处理方式。
我们可以回想一下官网的图:
vue 的响应式基本原理:
1、vue 会遍历此 data 中对象所有的属性,
2、并使用 Object.defineProperty 把这些属性全部转为 getter/setter,
3、而每个组件实例都有 watcher 对象,
4、它会在组件渲染的过程中把属性记录为依赖,
5、之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
2、亮点回答
概括回答我们只回答了使用 ES5 的方法 Object.defineProperty 实现数据的监听的,那么具体是如何实现还是没有讲的很清楚。
这时候我们需要问自己,如何找亮点?
vue 的响应式原理设计三个重要对象:Observer,Watcher,Dep。
Observer 对象:vue 中的数据对象在初始化过程中转换为 Observer 对象。
Watcher 对象:将模板和 Observer 对象结合在一起生成 Watcher 实例,Watcher 是订阅者中的订阅者。
Dep 对象:Watcher 对象和 Observer 对象之间纽带,每一个 Observer 都有一个 Dep 实例,用来存储订阅者 Watcher。
当属性变化会执行主题对象 Observer 的 dep.notify 方法, 这个方法会遍历订阅者 Watcher 列表向其发送消息, Watcher 会执行 run 方法去更新视图。
依赖关系图如下,更能方面我们的理解
接着我们需要补充的是:模板编译过程中的指令和数据绑定都会生成 Watcher 实例,实例中的 watch 属性也会生成 Watcher 实例。
说的这些有没有觉得有点乱,那我们总结一下如何亮点回答
1、在生命周期的 initState 方法中将 data,prop,method,computed,watch 中的数据劫持, 通过 observe 方法与 Object.defineProperty 方法将相关对象转为换 Observer 对象。
2、然后在 initRender 方法中解析模板,通过 Watcher 对象,Dep 对象与观察者模式将模板中的 指令与对象的数据建立依赖关系,使用全局对象 Dep.target 实现依赖收集。
3、当数据变化时,setter 被调用,触发 Object.defineProperty 方法中的 dep.notify 方法, 遍历该数据依赖列表,执行器 update 方法通知 Watcher 进行视图更新。
vue 是无法检测到对象属性的添加和删除,但是可以使用全局 Vue.set 方法(或 vm.$set 实例方法)。
vue 无法检测利用索引设置数组,但是可以使用全局 Vue.set 方法(或 vm.$set 实例方法)。
无法检测直接修改数组长度,但是可以使用 splice
然后写一个使用 Object.defineProperty 实现监听变量
如果上面代码格式出现问题,可以查看下面代码图片
3、进阶回答
因为现在 vue 已经到 3 了,不再是停留在 2 的时候,这个时候,可以把 3 的原理简单说一下。
这个时候不应该是 ES6 的 proxy 特性上场了,proxy 是 ES6 的新增的功能,可以用来定义对象中的操作。
如果上面代码格式出现问题,可以查看下面代码图片
可以很方便的使用 Proxy 来实现一个数据绑定和监听.
如果上面代码格式出现问题,可以查看下面代码图片
然后在对比 vue2 和 vue3 的区别是什么?
以及为啥在数据监听上做了升级?
vue 为什么对数组对象的深层监听无法实现,因为组件每次渲染都是将 data 里的数据通过 defineProperty 进行响应式或者双向绑定上,之前没有后加的属性是不会被绑定上,也就不会触发更新渲染。
区别:
1、语法层面上
defineProperty 只能响应首次渲染时候的属性,
Proxy 需要的是整体监听,不需要关心里面有什么属性,而且 Proxy 的配置项有 13 种,可以做更细致的事情,这是之前的 defineProperty 无法达到的。
2、兼容层面上
vue2.x 之所以只能兼容到 IE8 就是因为 defineProperty 无法兼容 IE8,其他浏览器也会存在轻微兼容问题。
proxy 的话除了 IE,其他浏览器都兼容,这次 vue3 还是使用了它,说明 vue3 直接放弃了 IE 的兼容考虑。
写在最后
每日一题,带你一起学习新技术,总结学习过程,让你进阶到高级资深工程师,学习项目管理,思考职业发展,生活感悟,充实中成长起来。问题或建议,请在文末留言评论。
评论