来源:原创
一、前言文章首发在「松宝写代码」
2020.12.23 日刚立的 flag,每日一题,题目类型不限制,可以是:算法题,面试题,阐述题等等。
本文是「每日一题」第 5 题:「每日一题」到底该如何回答:vue数据绑定的实现原理?
往期「每日一题」:
第 4 道「每日一题」与面试官手撕代码:如何科学高效的寻找重复元素?
第 3 道「「每日一题」面试官问你对 Promise 的理解?可能是需要你能手动实现各个特性」
第 2 道「[每日一题]ES6 中为什么要使用 Symbol?」
第 1 道「一道面试题是如何引发深层次的灵魂拷问?」
二、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实现监听变量
var obj = {}; var a; Object.defineProperty(obj, 'a', { get: function() { console.log('get val'); return a; }, set: function(newVal) { console.log('set val:' + newVal); a = newVal; } }); obj.a; // get val obj.a = 'saucxs' //set val如果上面代码格式出现问题,可以查看下面代码图片
3、进阶回答因为现在vue已经到3了,不再是停留在2的时候,这个时候,可以把3的原理简单说一下。