iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0
Vue.js

Vue3.6 的革新:深入理解 Composition API系列 第 6

Day 6: Proxy 的底層實現

  • 分享至 

  • xImage
  •  

Vue 3.5 的響應式系統是基於 ES6 Proxy ,它讓框架能「攔截物件操作 → 收集依賴 / 觸發更新」,但「Proxy 到底是什麼、怎麼運作」卻很抽象。

今天要來理解 Proxy 的概念,就能更清楚為什麼 ref / reactive 能自動更新 UI

什麼是 Proxy?


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 → 設值時的動作
  • 攔截其他操作(如 delete、has…)

這讓 Vue 可以「監控資料變化,並在變化時觸發 UI 更新」。

Proxy 運作示意圖


     使用者程式碼
          ↓
   ┌──────────────────┐
   │   Proxy 代理人   │   ← 攔截操作 (get / set)
   └──────────────────┘
          ↓
      真正的物件
  • 取值:你讀 state.count → Proxy 攔截 get → Vue 知道「這裡被使用了」→ 建立依賴關係
  • 設值:你改 state.count = 2 → Proxy 攔截 set → Vue 通知「這裡變了」→ 觸發 DOM 更新

簡單範例:原生 Proxy


// 原始資料
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

Vue 2 vs Vue 3 實作差異


前面提到這麼多內容,Proxy 在 Vue 3 中為什麼重要呢?
文字或許比較難說明,今天先用表格比對 Vue 2 和 Vue 3 實作差異:

特性 Vue 2 (Object.defineProperty) Vue 3 (Proxy)
監控屬性 只能監控已存在屬性 可攔截所有屬性(新增 / 刪除)
陣列方法 部分需要改寫 全面支援
初始化效能 大物件初始化慢 用到時才代理,更快
深層響應 需要遞迴遍歷 自動遞迴代理

實作上明顯可以看到 Proxy 讓 Vue 3.5 在 效能可維護性 上全面超越 Vue 2。

Proxy 在 Composition API 的角色


<script lang="ts" setup> 中,我們常用 reactiveref,怎麼從這裡看出 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>

從上面的範例觀察 背後發生的事:

  1. 讀取 count.value → Proxy 攔截 get → 建立依賴。
  2. 修改 count.value++ → Proxy 攔截 set → 通知 DOM 更新。
  3. 修改 state.age++ → Proxy 攔截 → 同樣觸發更新。

總結


  • Proxy = Vue 3 響應式的攔截器
  • get → 收集依賴。
  • set → 觸發更新。
  • 相比 Vue 2 的 Object.defineProperty,Proxy 更 完整 / 強大 / 高效
  • 它是 refreactive 的基石,讓 Composition API 成為可能

參考文件


  1. Proxy 實用的五種場景 - this.web
  2. vue配置proxy跨域代理 - GitCode 開源社區

上一篇
Day 5: 響應式資料 ref 和 reactive
系列文
Vue3.6 的革新:深入理解 Composition API6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言