Proxy 是 JavaScript 用于创建代理对象以拦截并自定义对象操作的内置构造函数,Vue 3 等框架基于其 get/set 等 trap 实现响应式,通过依赖收集(track)与触发更新(trigger)机制配合 WeakMap 管理依赖关系,克服了 Object.defineProperty 的诸多限制。

Proxy 是 JavaScript 提供的一个内置构造函数,用于创建一个代理对象,拦截并自定义对目标对象的基本操作(比如读取、赋值、删除属性等)。它本身不直接实现响应式,但它是现代前端框架(如 Vue 3、SolidJS)实现响应式系统的核心底层机制。
Proxy 能拦截哪些操作?
通过 handler 对象,你可以定义各种 trap(陷阱),覆盖默认行为。常用且与响应式强相关的包括:
-
get(target, key, receiver):拦截属性读取,比如
obj.x或obj['x'],适合在这里收集依赖(track) -
set(target, key, value, receiver):拦截属性赋值,比如
obj.x = 1,适合在这里触发更新(trigger) -
deleteProperty(target, key):拦截
delete obj.x -
has(target, key):拦截
key in obj -
ownKeys(target):拦截
Object.keys()、for...in等枚举操作
响应式更新的关键:依赖收集 + 触发通知
Proxy 本身只是“监听器”,真正实现响应式需要配合一套追踪机制:
- 每次
get时,把当前正在执行的副作用函数(如渲染函数)和这个 key 关联起来 → 这叫“依赖收集”(track) - 每次
set时,找出所有依赖该 key 的副作用函数并执行 → 这叫“触发更新”(trigger) - 通常用 WeakMap 存储 target → Map(key → Set
)结构来管理依赖关系
例如:const state = reactive({ count: 0 }),内部会用 Proxy 包裹 { count: 0 },当模板中访问 state.count 时触发 get,自动记下这个渲染函数;后续修改 state.count = 1 就触发 set,从而重跑渲染。
立即学习“Java免费学习笔记(深入)”;
为什么不用 Object.defineProperty?
Vue 2 使用 defineProperty 实现响应式,但它有明显局限:
AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。它不是新的编程语言,而是一种使用现有标准的新方法,最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容,不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。《php中级教程之ajax技术》带你快速
- 无法监听新增/删除属性(需
Vue.set/Vue.delete) - 无法监听数组索引赋值(
arr[0] = x)或 length 修改 - 对 Map、Set、WeakMap 等原生集合类型完全无能为力
Proxy 是对整个对象的操作拦截,天然支持动态属性、数组、甚至嵌套对象——只要在 get 中递归 reactive,就能实现深度响应式。
简单手写 reactive 示例(简化版)
以下代码展示核心思路(忽略数组、Symbol、嵌套等细节):
const depsMap = new WeakMap() // target → key → effects
function track(target, key) {
let deps = depsMap.get(target)
if (!deps) {
deps = new Map()
depsMap.set(target, deps)
}
let effects = deps.get(key)
if (!effects) {
effects = new Set()
deps.set(key, effects)
}
effects.add(activeEffect) // 当前正在执行的 effect 函数
}
function trigger(target, key) {
const deps = depsMap.get(target)?.get(key)
if (deps) deps.forEach(fn => fn())
}
let activeEffect = null
function effect(fn) {
activeEffect = fn
fn()
activeEffect = null
}
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key)
return Reflect.get(target, key)
},
set(target, key, val) {
const res = Reflect.set(target, key, val)
trigger(target, key)
return res
}
})
}
这样,effect(() => console.log(state.count)) 就会在 state.count 变化时自动重新执行。
不复杂但容易忽略:Proxy 拦截的是“操作”,不是“值”;响应式效果来自 get/set 中穿插的依赖逻辑,而不是 Proxy 自身变魔术。










