Vue.js响应式核心是Observer类,通过Object.defineProperty(Vue 2)或Proxy(Vue 3)递归劫持对象属性,为每个属性定义getter/setter以实现依赖收集与更新通知,并对嵌套对象、数组进行深层观测,但不支持Map/Set及初始化后新增属性的自动响应。

Vue.js 的响应式系统核心在于 Observer 类,它通过 递归劫持对象属性 实现数据变化的自动追踪。其本质是利用 Object.defineProperty(Vue 2)或 Proxy(Vue 3)为数据添加 getter/setter,从而在读取和修改时触发依赖收集与更新通知。
Observer 类的核心职责
Observer 并非直接监听整个对象,而是为每个被观测的对象创建一个实例,并完成三件事:
- 标记该对象已被观测(添加
__ob__属性,指向当前 Observer 实例) - 遍历对象所有自有可枚举属性,对每个属性调用
defineReactive - 若属性值是对象或数组,递归地为其创建 Observer 实例(实现深层响应式)
defineReactive:定义响应式属性的关键函数
该函数是响应式建立的最小单元,负责为单个属性设置 getter 和 setter:
- getter 中执行依赖收集(
Dep.target && dep.depend()),把当前 Watcher 记录进该属性对应的依赖池 - setter 中先比较新旧值,若变化则触发通知(
dep.notify()),并针对新值做响应式处理(如新值是对象,就 new Observer(val)) - 对数组等特殊类型,会重写其变异方法(如
push、splice),确保操作能触发更新
递归劫持的实现逻辑
所谓“递归劫持”,是指 Observer 不止处理第一层属性,还会深入子对象:
立即学习“前端免费学习笔记(深入)”;
- 当
defineReactive发现某属性值是纯对象或数组,会立即调用observe(value) -
observe函数先判断是否已存在__ob__,避免重复观测;若无,则 new Observer(value) - 这样就形成树状观测结构:父对象 Observer → 子对象 Observer → 孙对象 Observer…
- 注意:ES6 Map/Set 等原生集合类型在 Vue 2 中不支持响应式,需用
Vue.set或替换整个引用
限制与边界情况
递归劫持虽强大,但有明确限制:
- 初始化时不存在的属性不会被自动劫持(需用
Vue.set或this.$set) - 直接通过索引设置数组项(
vm.items[0] = {})或修改长度(vm.items.length = 0)无法触发更新 - 使用
Object.freeze()的对象跳过观测(observerState.shouldConvert = false) - 循环引用会导致无限递归,Observer 内部通过闭包缓存已观测对象来规避









