Vue3响应式原理【通俗理解】

核心流程就三步:

  1. 读取数据时:偷偷记录"谁在用我"(依赖收集/track)
  2. 修改数据时:通知所有用我的人"我变了"(派发更新/trigger)
  3. 用proxy来拦截"读取"和"修改"这两个动作。

Proxy 是什么

一句话:Proxy 是 JavaScript 原生提供的一个"拦截器",它能在你对一个对象做任何操作(读、写、删除、遍历......)的时候,插一脚进去,执行你自定义的逻辑。

打个比方:你去酒店前台拿快递,前台小姐姐就是 Proxy。你不能直接进仓库翻,所有操作都经过她。她可以在给你快递之前登记一下(依赖收集),也可以在你寄快递时通知别人(触发更新)。

基本语法

javascript 复制代码
const proxy = new Proxy(target, handler)
  • target:你要代理的原始对象
  • handler:一个对象,里面定义你要拦截哪些操作

handler 里常用的拦截方法(叫 trap):

javascript 复制代码
const obj = { name: '张三', age: 25 }

const proxy = new Proxy(obj, {
  // 拦截读取
  get(target, key) {
    console.log(`有人读取了 ${key}`)
    return target[key]
  },
  // 拦截写入
  set(target, key, value) {
    console.log(`有人把 ${key} 改成了 ${value}`)
    target[key] = value
    return true
  },
  // 拦截删除
  deleteProperty(target, key) {
    console.log(`有人删除了 ${key}`)
    delete target[key]
    return true
  },
  // 拦截 key in obj
  has(target, key) {
    console.log(`有人检查 ${key} 是否存在`)
    return key in target
  }
})

proxy.name          // 输出: 有人读取了 name → '张三'
proxy.age = 30      // 输出: 有人把 age 改成了 30
delete proxy.age    // 输出: 有人删除了 age
'name' in proxy     // 输出: 有人检查 name 是否存在

看到了吧,所有对 proxy 的操作都被你拦截了,你想在里面干啥都行。

为什么 Vue 3 要用 Proxy

先看 Vue 2 用的 Object.defineProperty 有什么问题:

javascript 复制代码
// Vue 2 的方式:逐个属性劫持
const data = { count: 0 }

Object.defineProperty(data, 'count', {
  get() {
    console.log('读取 count')
    return value
  },
  set(newVal) {
    console.log('修改 count')
    value = newVal
  }
})

// 问题1:新增属性监听不到
data.newProp = 'hello'  // 没有任何拦截,Vue 2 里必须用 Vue.set()

// 问题2:删除属性监听不到
delete data.count       // 没有任何拦截,Vue 2 里必须用 Vue.delete()

// 问题3:数组索引修改监听不到
const arr = [1, 2, 3]
arr[0] = 999            // 监听不到,Vue 2 里这个操作不会触发视图更新

再看 Proxy 怎么解决这些问题:

javascript 复制代码
const data = reactive({ count: 0 })

// 新增属性 → 自动触发 set trap ✅
data.newProp = 'hello'

// 删除属性 → 自动触发 deleteProperty trap ✅
delete data.count

// 数组操作 → 全部能拦截 ✅
const arr = reactive([1, 2, 3])
arr[0] = 999       // 触发 set
arr.push(4)         // 触发 set(length 和新索引都能捕获)

对比总结

复制代码
特性                    Object.defineProperty     Proxy
─────────────────────────────────────────────────────────
监听新增属性              ❌ 不行                   ✅ 可以
监听删除属性              ❌ 不行                   ✅ 可以
监听数组索引              ❌ 不行                   ✅ 可以
监听粒度                  单个属性                  整个对象
需要递归初始化             ✅ 需要深度遍历           ❌ 按需代理(懒递归)
性能                      初始化开销大              访问时才代理,更快

最后一点"懒递归"值得说一下。Vue 2 在初始化时必须递归遍历整个对象的所有嵌套属性,全部用 defineProperty 劫持一遍。而 Vue 3 的 Proxy 只在你真正访问到某个嵌套对象时,才对它创建代理:

javascript 复制代码
const state = reactive({
  user: {
    address: {
      city: '北京'
    }
  }
})

// 只有当你真正读到 state.user.address 时
// Vue 3 才会对 address 这个对象创建 Proxy
// 如果你从来不访问它,就不会有任何开销

这就是 Vue 3 性能更好的原因之一。

简单说,Proxy 就是 JavaScript 给你的一个"万能拦截器",Vue 3 用它来监听数据的一切变化,比 Vue 2 的方案更全面、更高效、代码也更简洁。

相关推荐
甲维斯1 分钟前
Opus5.0首测,瘫坐沙发!效果,时间,token皆无敌!
前端·人工智能
LVZ3 分钟前
Skill + PVM 绝了,AI 直接帮你搞定环境问题了
前端
颜进强7 分钟前
从零搭建私人 RAG 知识库:让项目决策真正“可检索、可追溯”
前端·后端·ai编程
颜进强10 分钟前
Embedding 模型介绍:热门模型对比与应用场景
前端·后端·ai编程
颜进强11 分钟前
LanceDB 基础使用:用 TypeScript 完成第一次向量检索
前端·后端·ai编程
xyphf_和派孔明13 分钟前
企业级微前端项目完整创建步骤,第二步:配置主应用
前端
默_笙18 分钟前
🔑 让 AI 学会"读"网页:我用 Cheerio 爬了一篇掘金文章,然后切成小块存进了向量库
前端·javascript
颜进强18 分钟前
Ollama 从入门到实践:本地模型运行、API 调用
前端·后端·ai编程
颜进强23 分钟前
Embedding 基础使用:用 Ollama 和 LangChain.js 生成文本向量
前端·后端·ai编程
颜进强27 分钟前
Vector Store 入门:什么是向量数据库,主流产品如何选择
前端·后端·ai编程