面试题答案
一键面试改进点
- 直接操作数组长度:在Vue 2中,通过
Object.defineProperty
对数组的length
属性进行响应式处理存在局限性,直接修改数组的length
属性不会触发视图更新。而Vue 3使用Proxy
可以直接对数组length
的变化做出响应,当修改length
时能自动更新视图。 - 新增数组方法的响应式:Vue 2中对一些数组的变异方法(如
push
、pop
、shift
、unshift
、splice
、sort
、reverse
)进行了重写来实现响应式,但对于非变异方法(如filter
、map
、forEach
等)返回的新数组不是响应式的。Vue 3的Proxy
可以对所有数组操作方法都进行拦截,无论是变异方法还是非变异方法,使得新生成的数组也具有响应式。
原理
Proxy
是ES6提供的用于创建对象代理的构造函数。它可以对目标对象的各种操作(如读取、赋值、枚举、函数调用等)进行拦截和自定义操作。在Vue 3中,利用Proxy
的这一特性,对数组的所有操作进行拦截。当数组发生变化时,Proxy
能够捕获到这些变化,然后通知依赖该数组的组件进行更新。
实现方式
在Vue 3中,reactive
函数内部会判断传入的值是否为数组,如果是数组则通过new Proxy(target, handler)
创建一个代理对象。其中handler
定义了各种拦截操作,例如:
const arrayProto = Array.prototype
const mutableHandlers = {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
// 收集依赖
track(target, TrackOpTypes.GET, key)
return res
},
set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)
if (oldValue !== value) {
// 触发更新
trigger(target, TriggerOpTypes.SET, key, value, oldValue)
}
return result
}
}
function reactive(target) {
return new Proxy(target, mutableHandlers)
}
对于数组的特定操作,如length
属性的修改、数组方法的调用等,Proxy
的handler
中都有相应的拦截逻辑,从而实现对数组的全面响应式处理。