Vue 2数据响应式原理
- Object类型数据:通过
Object.defineProperty()
方法对对象的每个属性进行劫持,在数据读取时进行依赖收集,数据变化时触发更新。例如:
let data = {name: 'John'};
Object.defineProperty(data, 'name', {
get() {
// 依赖收集
return value;
},
set(newValue) {
if (newValue!== value) {
value = newValue;
// 触发更新
}
}
});
- Array类型数据:对数组的7种变更方法(
push
、pop
、shift
、unshift
、splice
、sort
、reverse
)进行了重写,当调用这些方法时会触发视图更新。例如:
let arr = [1, 2, 3];
let arrayProto = Array.prototype;
let arrMethods = Object.create(arrayProto);
['push', 'pop'].forEach(method => {
arrMethods[method] = function() {
// 调用原生方法
arrayProto[method].apply(this, arguments);
// 触发更新
};
});
Vue 3数据响应式原理
- 使用Proxy:Vue 3利用ES6的
Proxy
来实现数据响应式。Proxy
可以直接代理整个对象,而不是像Vue 2那样对每个属性进行劫持。例如:
let data = {name: 'John'};
let proxy = new Proxy(data, {
get(target, property) {
// 依赖收集
return target[property];
},
set(target, property, value) {
target[property] = value;
// 触发更新
return true;
}
});
- Reflect:配合
Proxy
使用Reflect
,它提供了一系列与Proxy
处理程序方法相对应的方法,使代码更加简洁和规范。例如在set
操作中可以使用Reflect.set(target, property, value)
来代替直接赋值。
两者主要区别
- 实现方式:
- Vue 2使用
Object.defineProperty()
,对对象属性逐个劫持,对于新增属性需要手动调用Vue.$set
才能使其响应式。
- Vue 3使用
Proxy
,可以直接代理整个对象,对新增属性也能自动响应式。
- 性能:
- Vue 2在初始化时对对象的每个属性进行劫持,对于大型对象,初始化性能开销较大。
- Vue 3的
Proxy
是对整个对象代理,初始化性能相对较好,且在属性动态增减时性能更优。
- 兼容性:
- Vue 2由于使用
Object.defineProperty()
,兼容性较好,支持IE 9及以上。
- Vue 3使用
Proxy
,不支持IE浏览器。