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的兼容思考。

写在最初

每日一题,带你一起学习新技术,总结学习过程,让你进阶到高级资深工程师,学习项目管理,思考职业倒退,生存感悟,空虚中成长起来。问题或倡议,请在文末留言评论。