← 返回文章列表
JavaScript·162 次阅读

Proxy 与 Reflect:响应式系统的基石

Proxy 与 Reflect:响应式系统的基石

Vue 3 响应式的底层是 Proxy,而规范的 Proxy 写法离不开 Reflect。把两者一起讲透。

Proxy:对象操作的拦截器

Proxy 在目标对象外套一层代理,可拦截对象的几乎所有底层操作——不是只有读写:

const p = new Proxy(user, {
  get(target, key, receiver) {
    console.log('读取', key)
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    console.log('设置', key)
    return Reflect.set(target, key, value, receiver)
  },
  deleteProperty(target, key) {
    console.log('删除', key)
    return Reflect.deleteProperty(target, key)
  },
  has(target, key) { /* key in obj 的拦截 */ },
  ownKeys(target) { /* Object.keys / for...in 的拦截 */ },
})

可拦截的陷阱(trap)有 13 种,包括 apply(函数调用)、construct(new)、getPrototypeOf 等。

为什么必须用 Reflect

Reflect API 与 Proxy 陷阱一一对应,把对象底层操作变成函数调用。两个关键理由:

1. receiver 传递保证正确的 this 与响应式穿透

receiver 指向"正在操作的代理对象"。访问嵌套属性时,如果直接 return target[key],getter 内的 this 指向原始对象而非代理——深层响应式就断了。Reflect.get(target, key, receiver) 让 getter 中的 this 保持为代理,嵌套访问才能持续触发拦截(这也是 Vue 3 用 Reflect 的核心原因)。

2. 操作的返回值语义

Reflect.set/deleteProperty 返回布尔值表示是否成功(严格模式下手动赋值失败会抛异常,Reflect 则安静返回 false),陷阱中可以正确决定后续行为,且不会意外抛错。

与 defineProperty 的本质区别

  • defineProperty 劫持单个属性,Proxy 代理整个对象
  • Proxy 天然拦截新增属性、删除、数组下标、length
  • Proxy 无法 polyfill;Reflect 是 ES6 内置

最小响应式 Demo

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key, receiver) {
      track(target, key)
      const res = Reflect.get(target, key, receiver)
      return res !== null && typeof res === 'object' ? reactive(res) : res
    },
    set(target, key, value, receiver) {
      const res = Reflect.set(target, key, value, receiver)
      trigger(target, key)
      return res
    },
  })
}

这就是 Vue 3 reactive 的骨架。理解了 Proxy 13 个陷阱和 Reflect 的 receiver 语义,再读响应式源码会非常顺畅。

看到这里了?如果这篇文章帮到过你

请我喝瓶可乐就好 🥤

收款码

评论0 条

还没有评论,来抢沙发~

发表评论

评论需审核后显示

© 2026 许冬博客 · 专注 JS 技术分享

·RSS 订阅·Powered by Nuxt 4