📌 前言

如果说 Composition API 是 Vue3 的表象革新,那么:

响应式系统的重构,才是 Vue3 的灵魂升级。

Vue2 的响应式被无数开发者“吐槽过”:

  • ❌ 无法监听对象新增属性

  • ❌ 无法监听数组索引变化

  • $set/ $delete用得心累

而 Vue3 用 Proxy + Reflect​ 一次性解决了这些问题。

今天这篇文章,我们就从原理图 → 代码对比 → 手写简易版,彻底搞懂 Vue3 的响应式核心。


一、Vue2 响应式:Object.defineProperty 的局限

1️⃣ Vue2 响应式简化模型

function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    get() {
      // 依赖收集
      return val
    },
    set(newVal) {
      // 通知更新
      val = newVal
    }
  })
}

2️⃣ Vue2 的致命问题

问题

表现

新增属性

无法监听(需 Vue.set

删除属性

无法监听(需 Vue.delete

数组索引

无法监听

性能

初始化递归遍历所有属性

📌 根本原因

Object.defineProperty只能劫持已有属性


二、Vue3 响应式:Proxy 的降维打击

1️⃣ Proxy 是什么?

一句话解释:

Proxy 是对整个对象的“代理”,而不是对单个属性的“修补”。

const obj = { count: 0 }

const proxy = new Proxy(obj, {
  get(target, key, receiver) {
    console.log('get:', key)
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    console.log('set:', key, value)
    return Reflect.set(target, key, value, receiver)
  }
})

2️⃣ 拦截能力对比(重点)

行为

Vue2

Vue3

读取属性

新增属性

删除属性

数组索引

length 变化

Map / Set

Proxy 能拦截 13 种操作,几乎覆盖所有对象行为。


三、Reflect:为什么 Vue3 一定要用它?

1️⃣ Reflect 的作用

能力

说明

统一 API

替代 obj[key]

返回值语义

成功 / 失败

与 Proxy 完美配合

保证 receiver 正确指向

2️⃣ 错误示例 vs 正确示例

❌ 不推荐:

get(target, key) {
  return target[key]
}

✅ Vue3 推荐:

get(target, key, receiver) {
  return Reflect.get(target, key, receiver)
}

📌 原因

  • 保证 this指向正确

  • 兼容原型链

  • 行为更规范


四、Vue3 响应式原理图解(文字版)

组件渲染
   ↓
读取响应式数据(get)
   ↓
依赖收集(track)
   ↓
建立 数据 ↔ 组件 关联
   ↓
数据变化(set)
   ↓
触发依赖(trigger)
   ↓
组件重新渲染

📌 核心函数

  • reactive()→ 创建响应式对象

  • effect()→ 副作用函数(组件渲染)

  • track()→ 依赖收集

  • trigger()→ 触发更新


五、手写一个 Mini Vue3 响应式(面试高频)

1️⃣ 实现 reactive

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) {
      const result = Reflect.set(target, key, value, receiver)
      trigger(target, key)
      return result
    }
  })
}

2️⃣ 简化版 effect / track / trigger

const targetMap = new WeakMap()

function track(target, key) {
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    depsMap = new Map()
    targetMap.set(target, depsMap)
  }
  let dep = depsMap.get(key)
  if (!dep) {
    dep = new Set()
    depsMap.set(key, dep)
  }
  dep.add(effect)
}

function trigger(target, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)
  effects?.forEach(fn => fn())
}

let effect
effect = () => {
  console.log('组件重新渲染')
}

✅ 这就是 Vue3 响应式的最小实现模型


六、Vue3 响应式的三大优势总结

✅ 1. 真正的数据监听

const state = reactive({ count: 0 })
state.newProp = 123 // ✅ 可监听

✅ 2. 性能更好

  • 初始化时不递归

  • 访问时才代理

✅ 3. 代码更优雅

  • 不再需要 $set/ $delete

  • 心智负担大幅降低


七、面试高频问答(建议背)

Q1:Vue2 为什么不能监听新增属性?

因为 Object.defineProperty只能劫持已有属性。

Q2:Vue3 为什么用 Proxy?

Proxy 可以拦截整个对象,支持新增、删除、数组变化。

Q3:Reflect 的作用是什么?

提供统一的对象操作 API,保证 Proxy 行为正确。

更多推荐