vue响应式简单实现
响应式原理概述
Vue的响应式系统通过数据劫持结合发布-订阅模式实现。核心是利用Object.defineProperty(Vue 2)或Proxy(Vue 3)拦截对象属性的读写操作,在数据变化时自动触发依赖更新。

Vue 2 实现方式
基于Object.defineProperty实现数据劫持:
function defineReactive(obj, key, val) {
// 递归处理嵌套对象
observe(val);
const dep = new Dep(); // 依赖管理
Object.defineProperty(obj, key, {
get() {
Dep.target && dep.addSub(Dep.target); // 收集依赖
return val;
},
set(newVal) {
if (newVal === val) return;
observe(newVal); // 新值为对象时递归劫持
val = newVal;
dep.notify(); // 通知更新
}
});
}
function observe(obj) {
if (typeof obj !== 'object' || obj === null) return;
new Observer(obj);
}
class Observer {
constructor(obj) {
if (Array.isArray(obj)) {
// 数组响应式需特殊处理(重写方法)
} else {
Object.keys(obj).forEach(key => defineReactive(obj, key, obj[key]));
}
}
}
依赖管理类
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
Dep.target = null; // 静态属性指向当前Watcher
Vue 3 实现方式
基于Proxy的改进方案:
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key); // 依赖收集
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
trigger(target, key); // 触发更新
return true;
}
});
}
// 依赖跟踪与触发
const targetMap = new WeakMap();
function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) targetMap.set(target, (depsMap = new Map()));
let dep = depsMap.get(key);
if (!dep) depsMap.set(key, (dep = new Set()));
dep.add(activeEffect);
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
depsMap.get(key)?.forEach(effect => effect());
}
简单Watcher实现
let activeEffect;
class Watcher {
constructor(fn) {
this.fn = fn;
this.run();
}
run() {
activeEffect = this.fn;
this.fn();
activeEffect = null;
}
update() {
this.run();
}
}
// 使用示例
const data = reactive({ count: 0 });
new Watcher(() => console.log('Count:', data.count));
data.count++; // 自动触发日志输出
注意事项
- 性能优化:Proxy相比
Object.defineProperty无需递归初始化所有属性,按需响应。 - 数组处理:Vue 2需重写数组方法(push/pop等),Vue 3的Proxy可直接拦截数组索引变化。
- 局限性:Vue 2无法检测新增/删除属性(需用
Vue.set/Vue.delete),Proxy无此限制。
通过上述代码可实现基础的响应式系统,实际Vue源码还包含虚拟DOM、批量更新等优化逻辑。







