面试题答案
一键面试1. Vue响应式原理
Vue 通过 Object.defineProperty()
方法将数据转换为响应式数据。在数据对象的属性上定义 getter
和 setter
,当访问数据时触发 getter
,进行依赖收集;当数据变化时触发 setter
,通知依赖进行更新。
2. 计算属性的依赖收集和更新机制
- 依赖收集:计算属性在首次访问时,会执行其函数,并且在这个过程中,会将当前渲染函数(Watcher)添加到依赖列表中。例如:
computed: {
computedValue() {
return this.dataA + this.dataB;
}
}
当访问 computedValue
时,渲染函数会被收集为 dataA
和 dataB
的依赖。
- 更新机制:当
dataA
或dataB
变化时,它们的setter
被触发,通知依赖(即计算属性的Watcher)进行更新。计算属性的Watcher会重新计算其值,若值发生变化,才会触发后续更新。
3. 计算属性变化触发虚拟DOM更新过程
- 对比:当计算属性值改变后,Vue会重新渲染组件,生成新的虚拟DOM。新老虚拟DOM会通过
patch
算法进行对比。patch
算法主要通过遍历新旧虚拟DOM树,对比节点的标签、属性等,找出差异。 - 更新:根据对比结果,将差异应用到真实DOM上。例如,如果某个节点的文本内容改变,
patch
会直接更新该节点的文本,而不是重新创建整个节点。
4. 优化频繁变化依赖避免不必要虚拟DOM更新
- 缓存计算结果:可以手动缓存计算属性的结果,只有当依赖真正变化时才重新计算。例如:
let cachedComputedValue;
let lastDataA;
let lastDataB;
computed: {
computedValue() {
if (!cachedComputedValue || lastDataA!== this.dataA || lastDataB!== this.dataB) {
cachedComputedValue = this.dataA + this.dataB;
lastDataA = this.dataA;
lastDataB = this.dataB;
}
return cachedComputedValue;
}
}
- 使用
watch
代替部分计算属性:对于依赖频繁变化且不需要立即响应的情况,可以使用watch
来监听依赖变化,在合适时机手动处理,减少不必要的更新。例如:
data() {
return {
dataA: 0,
dataB: 0,
computedValue: 0
};
},
watch: {
dataA(newVal) {
this.updateComputedValue();
},
dataB(newVal) {
this.updateComputedValue();
}
},
methods: {
updateComputedValue() {
this.computedValue = this.dataA + this.dataB;
}
}
Vue源码相关部分说明
- 响应式原理:在
src/core/observer/index.js
中,Observer
类通过defineReactive
方法为数据对象的属性定义getter
和setter
实现响应式。 - 计算属性:在
src/core/instance/state.js
中,initComputed
方法处理计算属性,计算属性的Watcher在src/core/observer/watcher.js
中定义,其update
方法负责重新计算值。 - 虚拟DOM更新:
src/core/vdom/patch.js
中的patch
函数实现了虚拟DOM的对比和更新逻辑。