Vue响应式原理实现总结(数据劫持Object.defineProperty/Proxy+发布订阅者设计模式)
Vue的响应式主要分为
数据劫持和发布订阅模式
。Vue2用的是Object.defineProperty,而Vue3改用Proxy。数据劫持就是在访问或修改对象属性时进行拦截,然后触发相应的更新。发布订阅模式则是用来收集依赖(比如视图更新函数),当数据变化时通知这些依赖执行。
总结一下,关键点包括:
使用Object.defineProperty或Proxy进行数据劫持
。在getter中收集依赖(Watcher到Dep)
。在setter中触发Dep的通知,执行所有Watcher的更新
。发布订阅模式通过Dep和Watcher实现依赖管理
。
相关知识
数据劫持实现
以下是关于 Object.defineProperty()
和 Proxy
的详细介绍和对比:
一、Object.defineProperty()
1. 核心功能
- 定义:JavaScript 原生方法,用于直接在对象上定义新属性,或修改现有属性。
- 核心能力:通过
getter
和setter
拦截属性的读写操作。 - 兼容性:ES5+,支持所有现代浏览器及 IE9+。
2. 基本语法
Object.defineProperty(obj, prop, {
get() {
/* 读取属性时触发 */ },
set(newVal) {
/* 修改属性时触发 */ },
enumerable: true, // 可枚举
configurable: true // 可配置(如删除)
});
3. 典型用途
const data = {
count: 0 };
// 劫持属性
Object.defineProperty(data, "count", {
get() {
console.log("读取 count");
return this._count; // 使用临时变量存储值
},
set(newVal) {
console.log("修改 count");
this._count = newVal;
}
});
data.count = 1; // 输出 "修改 count"
console.log(data.count); // 输出 "读取 count" → 1
4. 局限性
场景 | 问题描述 |
---|---|
新增属性 | 无法劫持未预先定义的属性 |
数组索引修改 | 直接通过索引修改元素无法触发监听 |
数组方法(push等) | 需重写数组方法才能劫持 |
深层对象 | 需递归遍历所有属性,性能较差 |
二、Proxy
1. 核心功能
- 定义:ES6 新增的元编程特性,用于创建一个对象的代理,拦截并自定义对象的基本操作。
- 核心能力:拦截 13 种对象操作(如读写属性、删除属性、方法调用等)。
- 兼容性:ES6+,不支持 IE11 及更低版本。
2. 基本语法
const proxy = new Proxy(target, {
get(target, prop) {
/* 拦截属性读取 */ },
set(target, prop, value) {
/* 拦截属性修改 */ },
// 其他拦截器:deleteProperty、has、ownKeys 等
});
3. 典型用途
const data = {
count: 0 };
const proxy = new Proxy(data, {
get(target, prop) {
console.log(`读取 ${
prop}`);
return Reflect.get(target, prop);
},
set(target, prop, value) {
console.log(`修改 ${
prop} 为 ${
value}`);
return Reflect.set(target, prop, value);
}
});
proxy.co