BridgeCraft logobridgecraft
週報顧問服務作品集關於聯絡登入
聯絡

bridgecraft

從資料視覺化到 AI Agent,一直在找下一個 meta

文章主題指南週報顧問服務Labs作品集系統架構關於聯絡RSS

© 2026 BridgeCraft — Waiting7777. All rights reserved.

← 所有文章

初探 Vue 3.0 中的 Proxy

2020年8月15日 · Waiting7777 · 2 分鐘閱讀

Proxy

什麼是 Proxy ? 來看看 MDN:

const p = new Proxy(target, handler)

簡單的說就是在原本的 target 上設置 proxy ,你對 target 的操作如果符合 handler 的鉤子那就會先在 handler 中處理。 例如:

const target = {}
const handler = {
    get: function(obj, prop) {
        return prop in obj ? obj[prop] : 37
    }
}

const p = new Proxy(target, handler)
p.a = 1
p.b = 'test'

console.log(p.a, p.b)  // 1, 'test'
console.log(p.c)       // 37
console.log(a.c)       // undefined

console.log(target)    // { a: 1, b: 'test' }

在這例子中,有個對象 object,以及一個只有 get 的 handler 他會檢查 object 有沒有 prop,沒有的話就印 37,所以 p.c 才會印出 37,而其他對 p.a p.b 的操作都跟原本一樣,且對 proxy 的操作也會轉到原本的 target 上面。

目前 proxy 支援的攔截總共有 13 種,請看MDN

Vue 2.x 是如何實現 Data Reactive

遍歷撈完 data 中的數據,使用 Object.defineProperty() 劫持 getter 和 setter,在 getter 中做數據依賴的收集處理, 在 setter 中監聽數據變化,並通知訂閱當前數據的地方。Source Code

let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
        const value = getter ? getter.call(obj) : val
        if (Dep.target) {
        dep.depend()
        if (childOb) {
            childOb.dep.depend()
            if (Array.isArray(value)) {
            dependArray(value)
            }
        }
        }
        return value
    },
    set: function reactiveSetter (newVal) {
        const value = getter ? getter.call(obj) : val
        /* eslint-disable no-self-compare */
        if (newVal === value || (newVal !== newVal && value !== value)) {
        return
        }
        /* eslint-enable no-self-compare */
        if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
        }
        // #7981: for accessor properties without setter
        if (getter && !setter) return
        if (setter) {
        setter.call(obj, newVal)
        } else {
        val = newVal
        }
        childOb = !shallow && observe(newVal)
        dep.notify()
    }
})

這樣做有啥問題呢?

  • 無法檢測 object property 的添加或移除。由於 Vue 會在初始化的時候針對 object property 執行 getter/setter 轉化,所以 property 必須在 data 對象上存在才能轉換為響應式,對於後來新增的屬性,就要用 vm.$set。

  • 對於 array vue 也有其限制,

當你利用索引直接設置值時,vm.items[indexOfItem] = newValue

  • 當你直接修改 array 長度時,vm.items.length = newLength

這兩種情況都不會觸發響應的更新。

  • 當需要綁定的 object 很大時,因為需要遍歷搜索整個 object 可能導致效能問題。

Vue 3.0 中使用了 Proxy

下面分別用 Object.definePropety() 和 Proxy 實現數據響應

使用 Object.defineProperty():

class Observer {
    constructor(data) {
        for(let key of Object.keys(data)) {
            if(typeof data[key] === 'object') {
                data[key] = new Observer(data[key]);
            }
            Object.defineProperty(this, key, {
                enumerable: true,
                configurable: true,
                get() {
                    console.log('你訪問了' + key);
                    return data[key];
                },
                set(newVal) {
                    console.log('你設置了' + key);
                    console.log('新的' + key + '=' + newVal);
                    if(newVal === data[key]) {
                        return;
                    }
                    data[key] = newVal;
                }
            })
        }
    }
}

const obj = {
    name: 'app',
    age: '18',
    a: {
        b: 1,
        c: 2,
    },
}
const app = new Observer(obj);
app.age = 20; // 你設置了 age, 新的 age = 20
console.log(app.age); //  你訪問了 age, 20
app.newPropKey = '新屬性'; 
console.log(app.newPropKey); // 新屬性

看輸出可以得知,新屬性並沒有得到前面設置的 get() 跟 set() ,這也就是剛剛所說 Vue 2.x 的問題。

接下來看看 Proxy 版本:

const obj = {
    name: 'app',
    age: '18',
    a: {
        b: 1,
        c: 2,
    },
}
const p = new Proxy(obj, {
    get(target, propKey, receiver) {
        console.log('你訪問了' + propKey);
        return Reflect.get(target, propKey, receiver);
    },
    set(target, propKey, value, receiver) {
        console.log('你設置了' + propKey);
        console.log('新的' + propKey + '=' + value);
        Reflect.set(target, propKey, value, receiver);
    }
});
p.age = '20'; // 你設置了 age, 新的 age=20
console.log(p.age); // 你訪問了 age, 20
p.newPropKey = '新属性'; // 你設置了 newPropKey, 新的 newPropKey=新屬性
console.log(p.newPropKey); // 你訪問了 newPropKey, 新屬性

可以看到,新增的屬性並不需要重新設定數據響應,這是因為針對 Proxy 的操作本來就都會走到 handler 裡面做處理。

總結

  • Proxy 是用來操作物件的,而 Object.defineProperty() 是用來操作物件屬性的。

  • 在 Vue 3 中用了 Proxy 來更優雅的完成數據響應,也解決了 Vue 2.x 中的問題。

  • 聽說 Vue 3 正式版在今年8月就會正式上線了。

每週一篇 — 技術趨勢背後的商業邏輯

分享:

Waiting7777

WoW Arena 冠軍轉前端,用電競 meta 思維拆解技術趨勢。

關於作者

相關文章

YC 裡越來越多二次創業者 — AI 時代為什麼老手反而更吃香創業創投+4

YC 裡越來越多二次創業者 — AI 時代為什麼老手反而更吃香

為什麼 AI 時代反而讓「老手」更吃香?從 YC 的數據看 repeat founder 的優勢在哪,以及這對第一次創業的人有什麼啟示。

2026年8月12日 · Waiting7777 · 7 分鐘閱讀

繼續閱讀 →
OpenChamber:專為 AI Agent 設計的開發環境,跟 IDE 的差別在哪?AI Agents開發工具+5

OpenChamber:專為 AI Agent 設計的開發環境,跟 IDE 的差別在哪?

拆解 OpenChamber 的設計邏輯:為什麼 agent 需要專屬的開發環境、跟直接在 terminal 跑 Claude Code 有什麼本質差異,以及這個方向的商業潛力在哪。

2026年8月11日 · Waiting7777 · 8 分鐘閱讀

繼續閱讀 →
AI coding 工具燒錢有多快?Databricks 告訴你怎麼控成本AI開發工具+4

AI coding 工具燒錢有多快?Databricks 告訴你怎麼控成本

從「Databricks 燒完錢才搞出控制工具」這個角度切入,拆解 AI coding 工具的真實成本結構,以及企業在 scale up 後才發現的坑。對比 Rippling 同樣在燒錢後才蓋 ROI 工具,這是一個系統性問題。

2026年8月8日 · Waiting7777 · 7 分鐘閱讀

繼續閱讀 →

這篇文章對你有幫助嗎?

每週一篇 — 技術趨勢背後的商業邏輯

AI 產業在變什麼、工程師該注意什麼——拆清楚寄到你的信箱。