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的原理简略说一下。
这个时候不应该是ES6的proxy个性上场了,proxy是ES6的新增的性能,能够用来定义对象中的操作。
let p = new Proxy(target, handler);// `target` 代表须要增加代理的对象// `handler` 用来自定义对象中的操作
如果下面代码格局呈现问题,能够查看上面代码图片
能够很不便的应用 Proxy 来实现一个数据绑定和监听.
let onWatch = (obj, setBind, getLogger) => { let handler = { get(target, property, receiver) { getLogger(target, property) return Reflect.get(target, property, receiver); }, set(target, property, value, receiver) { setBind(value); return Reflect.set(target, property, value); } }; return new Proxy(obj, handler);};let obj = { saucxs: 1 }let valuelet p = onWatch(obj, (v) => { value = v}, (target, property) => { console.log(`Get '${property}' = ${target[property]}`);})p.saucxs = songEagle // bind `value` to `songEagle`p.saucxs // -> Get 'saucxs' = songEagle
如果下面代码格局呈现问题,能够查看上面代码图片
而后在比照vue2和vue3的区别是什么?
以及为啥在数据监听上做了降级?
vue为什么对数组对象的深层监听无奈实现,因为组件每次渲染都是将data里的数据通过defineProperty进行响应式或者双向绑定上,之前没有后加的属性是不会被绑定上,也就不会触发更新渲染。
区别:
1、语法层面上
- defineProperty只能响应首次渲染时候的属性,
- Proxy须要的是整体监听,不须要关怀外面有什么属性,而且Proxy的配置项有13种,能够做更粗疏的事件,这是之前的defineProperty无奈达到的。
2、兼容层面上
- vue2.x之所以只能兼容到IE8就是因为defineProperty无奈兼容IE8,其余浏览器也会存在轻微兼容问题。
- proxy的话除了IE,其余浏览器都兼容,这次vue3还是应用了它,阐明vue3间接放弃了IE的兼容思考。
写在最初
每日一题,带你一起学习新技术,总结学习过程,让你进阶到高级资深工程师,学习项目管理,思考职业倒退,生存感悟,空虚中成长起来。问题或倡议,请在文末留言评论。