vue observer实现
Vue Observer 实现原理
Vue 的响应式系统核心是通过 Observer 实现的,它利用 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)来劫持数据的变化,触发依赖更新。
Vue 2.x 的实现
在 Vue 2.x 中,Observer 通过递归遍历对象的属性,将其转换为响应式数据:
class Observer {
constructor(value) {
this.value = value;
this.dep = new Dep(); // 依赖收集器
def(value, '__ob__', this); // 标记为已观测
if (Array.isArray(value)) {
this.observeArray(value);
} else {
this.walk(value);
}
}
walk(obj) {
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i]);
}
}
observeArray(items) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i]);
}
}
}
function defineReactive(obj, key, val) {
if (arguments.length === 2) {
val = obj[key];
}
const dep = new Dep();
let childOb = observe(val); // 递归观测子属性
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
if (Dep.target) {
dep.depend(); // 收集依赖
if (childOb) {
childOb.dep.depend();
}
}
return val;
},
set(newVal) {
if (val === newVal) return;
val = newVal;
childOb = observe(newVal); // 新值也可能是对象,需重新观测
dep.notify(); // 通知更新
}
});
}
function observe(value) {
if (!value || typeof value !== 'object') return;
let ob;
if (value.hasOwnProperty('__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__;
} else {
ob = new Observer(value);
}
return ob;
}
Vue 3.x 的实现
Vue 3.x 改用 Proxy 实现响应式,解决了 Vue 2.x 中无法检测数组和对象新增属性的问题:
function reactive(target) {
const handler = {
get(target, key, receiver) {
track(target, key); // 依赖收集
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
const oldValue = target[key];
const result = Reflect.set(target, key, value, receiver);
if (oldValue !== value) {
trigger(target, key); // 触发更新
}
return result;
}
};
return new Proxy(target, handler);
}
function track(target, key) {
// 收集当前活跃的 effect(副作用函数)
if (activeEffect) {
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;
const effects = depsMap.get(key);
effects && effects.forEach(effect => effect());
}
核心差异
- Vue 2.x:基于
Object.defineProperty,需递归遍历对象属性,无法检测新增/删除属性,需通过Vue.set或Vue.delete处理。 - Vue 3.x:基于
Proxy,支持动态属性增删,性能更好,但需注意浏览器兼容性(IE 不支持)。







