关于程序员:每日一题抖音面试题请阐述vue数据绑定的实现原理

42次阅读

共计 2814 个字符,预计需要花费 8 分钟才能阅读完成。

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

写在最初

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

正文完
 0