Vue3 响应式系统底层之 Proxy 拦截器怎么写?手写简版响应式实战

舞夢輝影

舞夢輝影

2026-05-09

651人浏览

原创

proxy拦截器最核心、必写的两个操作是get和set:get用于读取时依赖收集,set用于写入时触发更新,二者共同构成响应式数据劫持的基础闭环。

vue3 响应式系统底层之 proxy 拦截器怎么写?手写简版响应式实战

Proxy 拦截器核心要拦截哪些操作?

Vue3 响应式底层用 Proxy 代替了 Vue2 的 Object.defineProperty,关键在于精准拦截对象的读取(get)和写入(set)行为,同时还要处理删除(deleteProperty)、in 检查、遍历(ownKeys)、数组索引/长度变更等。但最核心、必写的两个是:getset

手写简版 reactive:基础 Proxy + 依赖收集

响应式本质 = 数据劫持 + 依赖追踪 + 触发更新。我们聚焦 Proxy 部分,先忽略 effect、track、trigger 的完整调度逻辑,写出可运行的最小闭环:

✅ 关键点:

  • get 拦截器:读取属性时,自动将当前副作用函数(如 render)与该属性建立联系(依赖收集)
  • set 拦截器:修改属性时,通知所有依赖该属性的副作用函数重新执行
  • 递归代理:对嵌套对象/数组也返回 reactive,保证深层响应式
  • 避免重复代理:已代理的对象直接返回,防止无限递归

代码示例(精简可运行版):

Vue-router参考手册
Vue-router参考手册

Vue-router参考手册下载

下载
const toProxy = new WeakMap() // 缓存已代理对象,避免重复
const toRaw = new WeakMap()    // 反向映射:代理 → 原对象

function reactive(target) {
  if (!isObject(target)) return target
  if (toProxy.has(target)) return toProxy.get(target)
  if (toRaw.has(target)) return target

  const handler = {
    get(target, key, receiver) {
      const res = Reflect.get(target, key, receiver)
      // ✅ 依赖收集:这里假设有个 activeEffect 存储当前正在执行的副作用
      if (activeEffect && key !== '__v_isReactive') {
        track(target, key) // 把 activeEffect 记录到 target.key 的依赖列表中
      }
      // ✅ 深度代理:对对象/数组属性自动 reactive
      return isObject(res) ? reactive(res) : res
    },

    set(target, key, value, receiver) {
      const oldVal = target[key]
      const res = Reflect.set(target, key, value, receiver)
      // ✅ 触发更新:只要值变了(排除 NaN === NaN 场景),就通知依赖
      if (value !== oldVal && (oldVal === oldVal || value === value)) {
        trigger(target, key) // 通知 target.key 的所有依赖执行
      }
      return res
    },

    deleteProperty(target, key) {
      const res = Reflect.deleteProperty(target, key)
      if (res) trigger(target, key)
      return res
    },

    ownKeys(target) {
      track(target, 'length' in target ? 'length' : ITERATE_KEY)
      return Reflect.ownKeys(target)
    }
  }

  const observed = new Proxy(target, handler)
  toProxy.set(target, observed)
  toRaw.set(observed, target)
  return observed
}

几个容易踩坑的细节

Proxy 不是万能的,写拦截器时要注意边界情况:

  • 数组索引赋值arr[0] = x)和 length 修改都会触发 set,但 push/pop/shift/unshift 等方法内部会改 length 和索引,需额外在 set 中判断是否为数组并处理 length 变更
  • for...in / Object.keys() 会触发 ownKeys,必须在这里调用 track,否则新增属性后遍历不更新
  • in 操作符 触发 has 拦截器,也要 track,否则 key in obj 响应不及时
  • 原始值无法代理:Proxy 只能代理对象,所以 reactive(123)reactive(null) 应直接返回原值
  • 避免死循环:在 set 中调用 trigger 后,若副作用里又修改同一属性,需用调度队列或标志位防无限递归

补充:ref 的 Proxy 实现思路

ref(x) 本质是一个带 .value 的响应式包装器。它内部其实也是 Proxy —— 对一个只有 value 属性的普通对象做代理:

function ref(value) {
  const refObject = { value }
  return new Proxy(refObject, {
    get(target, key) {
      if (key === 'value') track(refObject, key)
      return target[key]
    },
    set(target, key, newVal) {
      if (key === 'value') {
        target[key] = newVal
        trigger(refObject, key)
        return true
      }
      return false
    }
  })
}

这样就能让 ref.value 支持响应式读写,且保持和 reactive 统一的依赖系统。

前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!

相关专题

更多
python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1111

5

前端如何实现即时通讯
前端如何实现即时通讯

实现即时通讯的方法有WebSocket、Long Polling、Server-Sent Events、WebRTC等等。详细介绍:1、WebSocket,它可以在客户端和服务器之间建立持久连接,实现实时的双向通信,前端可以使用 WebSocket API来创建WebSocket连接,并通过发送和接收消息来实现即时通讯;2、Long Polling,是一种模拟实时通信的技术等等。

2023.10.09

2285

6

前端和后端的区别
前端和后端的区别

前端关注的是用户界面的设计和交互,而后端则注重数据处理和逻辑控制。想了解更多前端后端的相关内容,可以阅读本专题下面的文章。

2024.03.19

2154

13

php和前端的关联介绍
php和前端的关联介绍

php既可以作为前端语言,也可以作为后端语言。想了解更多php和前端的相关内容,可以阅读本专题下面的文章。

2024.03.22

2345

10

前端外包工作内容有哪些
前端外包工作内容有哪些

前端外包工作内容包括:1. 网站和应用程序开发;2. 用户界面和交互设计;3. 用户体验优化;4. 设计和视觉开发;5. 跨浏览器兼容性;6. 性能优化;7. 维护和更新;8. 项目管理和沟通。想了解更多前端的相关内容,可以阅读本专题下面的文章。

2024.05.22

357

5

vue2.0和3.0区别
vue2.0和3.0区别

vue2.0和3.0区别:vue2的响应式原理是利⽤“Object.defineProperty()”对数据进⾏劫持结合发布订阅模式的⽅式来实现,vue3中使⽤了es6的proxy API对数据代理,实现对数据的监控。本专题为大家提供vue2.0和3.0区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.17

943

5

vue3的生命周期有哪些
vue3的生命周期有哪些

vue3的生命周期:1、beforecreate;2、created;3、beforemount;4、mounted;5、beforeupdate;6、updated;7、beforedestroy;8、destroyed;9、activated;10、deactivated等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

10619

5

Vue3组合式API与组件开发实战
Vue3组合式API与组件开发实战

本专题讲解 Vue 3 组合式 API 的核心概念与应用技巧,深入分析响应式系统、生命周期管理、组件设计与复用策略。通过完整项目案例,指导前端开发者实现高性能、结构清晰的 Vue 应用,提升开发效率与代码可维护性。

2026.02.10

153

23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
uni-app快速上手
uni-app快速上手

共0课时 | 0人学习

Vue 教程
Vue 教程

共42课时 | 15.5万人学习

Vue3.x 工具篇--十天技能课堂
Vue3.x 工具篇--十天技能课堂

共26课时 | 2.2万人学习