共计 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 的兼容思考。
写在最初
每日一题,带你一起学习新技术,总结学习过程,让你进阶到高级资深工程师,学习项目管理,思考职业倒退,生存感悟,空虚中成长起来。问题或倡议,请在文末留言评论。