Vue 3.5 的響應式系統是基於 ES6 Proxy ,它讓框架能「攔截物件操作 → 收集依賴 / 觸發更新」,但「Proxy 到底是什麼、怎麼運作」卻很抽象。
今天要來理解 Proxy 的概念,就能更清楚為什麼 ref / reactive 能自動更新 UI。
Proxy 是一種設計模式,用來建立一個對原始物件的代理。它提供了一種對其進行控制的方式,通常用於當需要對物件進行額外的處理時,Proxy 可以攔截對原始物件的請求,並在執行這些請求之前或之後執行附加的邏輯。
Proxy 的主要功能包括:
JavaScript 中的 Proxy 是一種對內建物件進行代理的語法,允許開發者攔截對物件屬性讀取、寫入、函式呼叫等操作。
以下範例說明,Proxy 攔截了對 message 屬性的訪問和修改,並附加了一些額外的邏輯來記錄操作。
const target = {
    message: "Hello, Proxy!"
};
const handler = {
    get: function(target, prop, receiver) {
        console.log(Getting property "${prop}");
        return Reflect.get(target, prop, receiver);
    },
    set: function(target, prop, value) {
        console.log(Setting property "${prop}" to "${value}");
        target[prop] = value;
        return true;
    }
};
const proxy = new Proxy(target, handler);
console.log(proxy.message);  // 輸出: Getting property "message" \n Hello, Proxy!
proxy.message = "Hello, World!";  // 輸出: Setting property "message" to "Hello, World!"
console.log(proxy.message);  // 輸出: Getting property "message" \n Hello, World!
簡單來說,Proxy 就像一個中間人(攔截器)。
當你對某個物件做「存取 / 設定」動作時,不是直接操作物件,而是經過這個代理(Proxy),代理可以:
get → 取值時的動作set → 設值時的動作這讓 Vue 可以「監控資料變化,並在變化時觸發 UI 更新」。
     使用者程式碼
          ↓
   ┌──────────────────┐
   │   Proxy 代理人   │   ← 攔截操作 (get / set)
   └──────────────────┘
          ↓
      真正的物件
state.count → Proxy 攔截 get → Vue 知道「這裡被使用了」→ 建立依賴關係state.count = 2 → Proxy 攔截 set → Vue 通知「這裡變了」→ 觸發 DOM 更新// 原始資料
const obj = { count: 0 }
// 建立代理
const proxy = new Proxy(obj, {
  get(target, key) {
    console.log(`讀取屬性 ${key}:`, target[key])  // => 讀取屬性 count: 0
    return target[key]
  },
  set(target, key, value) {
    console.log(`修改屬性 ${key} 為`, value)  // => 修改屬性 count 為 5
    target[key] = value
    // 這裡可以觸發「通知 UI 更新」
    return true
  }
})
// 測試
console.log(proxy.count)  // 觸發 get
proxy.count = 5           // 觸發 set
前面提到這麼多內容,Proxy 在 Vue 3 中為什麼重要呢?
文字或許比較難說明,今天先用表格比對 Vue 2 和 Vue 3 實作差異:
| 特性 | Vue 2 (Object.defineProperty) | 
Vue 3 (Proxy) | 
|---|---|---|
| 監控屬性 | 只能監控已存在屬性 | 可攔截所有屬性(新增 / 刪除) | 
| 陣列方法 | 部分需要改寫 | 全面支援 | 
| 初始化效能 | 大物件初始化慢 | 用到時才代理,更快 | 
| 深層響應 | 需要遞迴遍歷 | 自動遞迴代理 | 
實作上明顯可以看到 Proxy 讓 Vue 3.5 在 效能 與 可維護性 上全面超越 Vue 2。
在 <script lang="ts" setup> 中,我們常用 reactive 和 ref,怎麼從這裡看出 Proxy 在 Composition API 扮演什麼樣的角色呢?
<script lang="ts" setup>
import { reactive, ref } from 'vue'
const count = ref<number>(0)  // 本質:value 被 Proxy 攔截
const state = reactive({ user: 'kuku', age: 25 })  // 本質:整個物件被 Proxy 包裝
function increment() {
  count.value++
  state.age++
}
</script>
<template>
  <p>{{ count }}</p>
  <p>{{ state.user }} ({{ state.age }})</p>
  <button @click="increment">+1</button>
</template>
從上面的範例觀察 背後發生的事:
count.value → Proxy 攔截 get → 建立依賴。count.value++ → Proxy 攔截 set → 通知 DOM 更新。state.age++ → Proxy 攔截 → 同樣觸發更新。get → 收集依賴。set → 觸發更新。Object.defineProperty,Proxy 更 完整 / 強大 / 高效。ref 和 reactive 的基石,讓 Composition API 成為可能。