面试题答案
一键面试相较于Vue 2.0的重大改进
- 深度监听:
- 在Vue 2.0中,使用
Object.defineProperty
对对象属性进行监听,对于对象嵌套多层的情况,需要递归遍历进行深度监听,性能开销较大。例如,对于obj.a.b.c
这样的嵌套结构,需要对a
、b
、c
逐层设置监听。 - Vue 3.0的
Proxy
是对整个对象进行代理,无需递归遍历,天然支持深度监听,大大简化了监听逻辑,提高了初始化性能。
- 在Vue 2.0中,使用
- 动态响应:
- Vue 2.0中,新增或删除对象属性时,需要使用
Vue.set
和Vue.delete
方法才能触发响应式更新,因为Object.defineProperty
无法监听到属性的动态添加和删除。 - 而
Proxy
可以监听到对象属性的动态添加和删除操作,使得数据的响应式处理更加灵活和自然,无需额外的特殊方法。
- Vue 2.0中,新增或删除对象属性时,需要使用
- 数组监听:
- Vue 2.0对数组的监听是通过重写数组的原型方法(如
push
、pop
等)来实现响应式。这种方式虽然能满足基本需求,但在一些特殊场景下不够灵活,比如直接通过索引修改数组元素(arr[0] = 'new value'
),需要使用Vue.set
才能触发更新。 - Vue 3.0的
Proxy
可以直接监听数组的变化,包括通过索引修改元素等操作,使数组的响应式处理更统一和高效。
- Vue 2.0对数组的监听是通过重写数组的原型方法(如
对性能优化的积极影响
- 初始化性能提升:由于
Proxy
无需递归深度监听,在初始化包含大量嵌套数据的对象时,性能显著提高。例如在一个具有复杂树形结构数据的应用中,Vue 3.0初始化数据的速度会比Vue 2.0快很多,减少了页面加载时间。 - 更新性能优化:动态响应的改进使得数据更新时,能更精准地触发视图更新。例如在频繁添加或删除对象属性的场景下,Vue 3.0能更高效地处理响应式,避免了Vue 2.0中因无法自动监听属性增减而导致的不必要的性能损耗。同时,对于数组操作的统一监听,也使得数组相关的更新操作性能更好。
从源码角度分析Proxy实现高效响应式追踪
- 创建Proxy实例:
- 在Vue 3.0的
reactive
函数中,会创建一个Proxy
实例。例如:
function reactive(target) { return new Proxy(target, { get(target, key) { // 依赖收集 track(target, key); return Reflect.get(target, key); }, set(target, key, value) { const result = Reflect.set(target, key, value); // 触发更新 trigger(target, key); return result; } }); }
- 在Vue 3.0的
- 依赖收集(
track
函数):- 在
get
拦截器中,通过track
函数进行依赖收集。它会将当前正在执行的副作用函数(如组件的渲染函数、计算属性的求值函数等)收集到与target
和key
相关的依赖集合中。 - 例如,通过一个全局的
activeEffect
变量来记录当前正在执行的副作用函数,然后将其添加到对应的依赖桶(WeakMap
结构)中。
- 在
- 触发更新(
trigger
函数):- 在
set
拦截器中,当数据发生变化时,通过trigger
函数触发更新。它会从依赖桶中取出与target
和key
相关的所有副作用函数,并依次执行,从而更新视图或重新计算计算属性的值。 - 这样,通过
Proxy
的拦截机制,结合依赖收集和触发更新的逻辑,实现了高效的响应式追踪。
- 在