在 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.defineProperty) | Vue 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 + defineReactive | Proxy + Reflect |
| 是否修改原对象 | ✅ 是 | ❌ 否(返回代理) |
| 依赖收集机制 | Dep 依赖对象管理 | effect 与 ReactiveEffect |
| 性能 | 递归深度有限,手动劫持 | 自动深层追踪,性能更优 |
| 支持数组与新增属性 | 部分支持,需 hack | 原生支持 |
| 是否推荐使用 | 适合小项目 | 推荐使用 reactive() |
七、总结与理解
Vue.observable() 的意义不在于替代 Vuex,而在于让我们更直观地理解 Vue 响应式系统的底层原理:
- Vue 2 时代通过
Object.defineProperty劫持属性; - Vue 3 时代使用
Proxy代理整个对象; - 无论哪种实现,本质都是让数据变化能“通知”依赖它的地方更新。
它让一个对象“有了生命”,能被观察、能被追踪,也能驱动界面自动响应。
本文内容由人工智能生成,仅供学习与参考使用,请在实际应用中结合自身情况进行判断。