深入理解 Vue.observable:Vue 2 与 Vue 3 的响应式核心机制对比

234 阅读4分钟

在 Vue 的世界里,“响应式”是它最核心的特性之一。而 Vue.observable() 作为一个轻量化的响应式状态工具,正好体现了 Vue 响应系统的精髓。

本文将带你从使用方式到源码原理,全面理解 Observable 在 Vue 2 与 Vue 3 中的设计理念、实现机制与区别


一、什么是 Observable

Observable(可观察的) ,顾名思义,就是让一个普通对象具备「被观察」的能力 —— 当它的属性发生变化时,依赖它的视图或计算属性能自动更新。

Vue 提供的 API:

Vue.observable(object)

作用说明

  • 将一个普通对象转为 响应式对象
  • Vue 内部在处理组件的 data() 返回对象时,也会用到这一机制。
  • 返回的对象可直接在模板或计算属性中使用,当属性变更时自动触发更新。
  • 可用于 轻量级全局状态管理,作为简单场景下的“mini Vuex”。

二、使用场景:跨组件共享状态

在复杂度不高的项目中,使用 Vuex 或 event bus 来做状态共享显得有些重型。
这时,Vue.observable() 提供了简洁优雅的替代方案。

示例

store.js

import Vue from 'vue'

// 创建响应式 state 对象
export const state = Vue.observable({
  name: '张三',
  age: 38
})

// 创建修改 state 的方法
export const mutations = {
  changeName(name) {
    state.name = name
  },
  setAge(age) {
    state.age = age
  }
}

组件中使用

<template>
  <div>
    姓名:{{ name }}<br />
    年龄:{{ age }}<br />
    <button @click="changeName('李四')">改变姓名</button>
    <button @click="setAge(18)">改变年龄</button>
  </div>
</template>

<script>
import { state, mutations } from '@/store'

export default {
  computed: {
    name() {
      return state.name
    },
    age() {
      return state.age
    }
  },
  methods: {
    changeName: mutations.changeName,
    setAge: mutations.setAge
  }
}
</script>

这样就实现了全局可响应的共享状态,无需 Vuex。


三、Vue 2 中的实现原理

Vue 2 的响应式系统基于 Object.defineProperty() ,核心逻辑位于 src/core/observer/index.js

1. 核心入口:observe()

export function observe(value, asRootData) {
  if (!isObject(value) || value instanceof VNode) return

  let ob
  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ob = value.__ob__
  } else if (
    shouldObserve &&
    (Array.isArray(value) || isPlainObject(value)) &&
    Object.isExtensible(value) &&
    !value._isVue
  ) {
    ob = new Observer(value) // 创建 Observer 实例
  }

  if (asRootData && ob) ob.vmCount++
  return ob
}

核心逻辑:如果对象还没被观测过,就用 Observer 包装它,使其变成响应式。


2. Observer

export class Observer {
  constructor(value) {
    this.value = value
    this.dep = new Dep() // 依赖收集器
    def(value, '__ob__', this)

    if (Array.isArray(value)) {
      protoAugment(value, arrayMethods)
      this.observeArray(value)
    } else {
      this.walk(value) // 遍历对象的每个属性
    }
  }

  walk(obj) {
    Object.keys(obj).forEach(key => defineReactive(obj, key))
  }
}

walk() :遍历对象的每个 key,并通过 defineReactive 把属性转成响应式。


3. defineReactive:响应式的核心

export function defineReactive(obj, key, val) {
  const dep = new Dep()
  let childOb = observe(val) // 递归观测子对象

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get() {
      const value = val
      if (Dep.target) { // 收集依赖
        dep.depend()
        if (childOb) childOb.dep.depend()
      }
      return value
    },
    set(newVal) {
      if (newVal === val) return
      val = newVal
      childOb = observe(newVal)
      dep.notify() // 通知依赖更新
    }
  })
}

简化解释
每个属性都被包裹成一个“可观察”的 getter/setter。
当读取时收集依赖,当修改时通知更新。


四、Vue 3 中的实现对比

Vue 3 放弃了 Object.defineProperty() 的方案,全面采用 Proxy + Reflect 实现响应式。
因此 Vue.observable() 在 Vue 3 中其实等价于:

import { reactive } from 'vue'

const state = reactive({ count: 1 })

区别对比

特性Vue 2(Object.definePropertyVue 3(Proxy
响应方式通过 defineProperty 劫持属性通过 Proxy 代理整个对象
新增/删除属性不能被自动追踪可以被自动追踪
数组响应通过重写数组原型方法实现天然支持
返回值改变原对象本身返回代理对象
性能与灵活性较低,需深层递归高,自动追踪深层结构

Vue 3 的 reactive() 是真正意义上的“可观察代理对象”,而 Vue 2 的 Vue.observable() 是直接“修改原对象”,两者的实现思想完全不同。


五、总结:Vue.observable 的价值

使用场景优点缺点
轻量级跨组件状态共享简单,无需引入 Vuex不支持持久化与模块化
小型全局状态存储无依赖,轻量无调试工具,难管理大型状态
Vue 2 与 Vue 3 通用理念都是基于响应式系统底层实现机制不同

可以把它理解为一个“极简版 Vuex”:
它让你在无需状态管理库的情况下,也能快速实现全局共享与自动更新。


六、核心总结表

概念Vue 2 实现Vue 3 实现
入口函数Vue.observable(obj)reactive(obj)
内部机制Observer + defineReactiveProxy + Reflect
是否修改原对象✅ 是❌ 否(返回代理)
依赖收集机制Dep 依赖对象管理effectReactiveEffect
性能递归深度有限,手动劫持自动深层追踪,性能更优
支持数组与新增属性部分支持,需 hack原生支持
是否推荐使用适合小项目推荐使用 reactive()

七、总结与理解

Vue.observable() 的意义不在于替代 Vuex,而在于让我们更直观地理解 Vue 响应式系统的底层原理:

  • Vue 2 时代通过 Object.defineProperty 劫持属性;
  • Vue 3 时代使用 Proxy 代理整个对象;
  • 无论哪种实现,本质都是让数据变化能“通知”依赖它的地方更新。

它让一个对象“有了生命”,能被观察、能被追踪,也能驱动界面自动响应。


本文内容由人工智能生成,仅供学习与参考使用,请在实际应用中结合自身情况进行判断。