面试题答案
一键面试- Vue响应式原理概述
- Vue通过数据劫持结合发布者 - 订阅者模式的方式,来实现数据的响应式更新。当数据发生变化时,Vue能够自动更新与之相关的DOM。
- Object.defineProperty方法
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。其语法为Object.defineProperty(obj, prop, descriptor)
,其中obj
是要定义属性的对象,prop
是要定义或修改的属性的名称,descriptor
是将被定义或修改的属性描述符。- 属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由一对 getter - setter 函数功能来描述的属性。
- 数据劫持实现过程
- 初始化阶段:
- 在Vue实例创建时,会遍历data对象中的所有属性。对于每个属性,使用
Object.defineProperty()
方法进行数据劫持。例如,假设有一个Vue实例如下:
- 在Vue实例创建时,会遍历data对象中的所有属性。对于每个属性,使用
- 初始化阶段:
let data = {
message: 'Hello Vue'
};
let vm = new Vue({
data: data
});
- 在内部,Vue会类似这样处理:
function defineReactive(data, key, value) {
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
// 这里可以进行依赖收集,例如收集当前正在使用该数据的Watcher
return value;
},
set: function reactiveSetter(newVal) {
if (newVal === value) return;
value = newVal;
// 当数据变化时,通知所有依赖该数据的Watcher进行更新
// 这里就是实现响应式更新的关键,会触发视图更新
}
});
}
for (let key in data) {
defineReactive(data, key, data[key]);
}
- 依赖收集:
- 在
get
函数中,会进行依赖收集。Vue维护了一个依赖关系图,每个数据(属性)都对应着一个依赖数组(存放Watcher)。当某个数据被读取时(例如在模板中使用该数据),当前的Watcher(通常与一个组件实例相关联,负责更新组件视图)会被添加到该数据的依赖数组中。
- 在
- 更新阶段:
- 当执行
set
函数时,如果新值与旧值不同,首先更新内部的数据值。然后遍历该数据的依赖数组,通知所有依赖该数据的Watcher。Watcher接收到通知后,会重新计算相关的渲染函数,从而触发视图的更新,实现了数据的响应式更新。
- 当执行
通过上述基于 Object.defineProperty()
的数据劫持方式,Vue有效地实现了数据的响应式,使得开发者可以专注于数据的变化,而Vue负责自动更新视图。