vue2的Object.definePropetry() 與 vue3的Proxy()

特性 Vue2 (Object.defineProperty) Vue3 (Proxy)
監(jiān)聽范圍 僅能監(jiān)聽已聲明屬性,新增屬性需 $set 監(jiān)聽整個對象,自動支持新增/刪除屬性
數(shù)組支持 需重寫 push/splice 等方法 原生數(shù)組操作自動響應(yīng),無需額外處理
嵌套對象 需遞歸遍歷手動綁定 自動深層代理(非淺響應(yīng)式時)
性能 初始化時遞歸遍歷所有屬性 懶代理(訪問時才代理嵌套對象)

1、proxy的核心攔截能力

與直接操作對象不同,Proxy 會創(chuàng)建一個代理層,所有對數(shù)據(jù)的訪問和修改都需經(jīng)過這層攔截,從而實現(xiàn)依賴收集與更新觸發(fā)。

vue3主要使用一下幾種實現(xiàn)方式:

  • get攔截:訪問屬性時觸發(fā),用于依賴收集。當(dāng)模板或者watch訪問響應(yīng)式數(shù)據(jù)時,get攔截器會記錄當(dāng)前依賴(如組件渲染的函數(shù)),建立數(shù)據(jù)與依賴的關(guān)聯(lián)。
  • set攔截:修改屬性時觸發(fā),用于觸發(fā)更新。當(dāng)數(shù)據(jù)變化時,set攔截器會通知所有依賴(如重新渲染組件)
  • deleteProperty攔截:刪除屬性時觸發(fā),確保刪除操作也能觸發(fā)響應(yīng)式更新。
  • has攔截:攔截in操作符(key in obj) 支持對屬性存在性的響應(yīng)式判斷
const obj = { count: 0 };
const proxy = new Proxy(obj, {
  get(target, key) {
    console.log(`訪問了 ${key}`); // 依賴收集
    return Reflect.get(target, key); // 使用 Reflect 保持 this 指向正確
  },
  set(target, key, value) {
    console.log(`修改了 ${key} 為 ${value}`); // 觸發(fā)更新
    return Reflect.set(target, key, value);
  }
});
proxy.count++; // 輸出:訪問了 count → 修改了 count 為 1

2、Object.defineProperty()的核心攔截能力

Vue 2 的響應(yīng)式系統(tǒng)核心依賴 Object.defineProperty 方法,通過劫持對象屬性的讀寫操作實現(xiàn)數(shù)據(jù)驅(qū)動視圖。其工作原理是遞歸遍歷 data 中的所有屬性,為每個屬性添加 getter/setter 攔截器,在屬性被訪問時收集依賴(如組件渲染函數(shù)),在屬性被修改時觸發(fā)更新(通知依賴重新執(zhí)行)

  • get 攔截:當(dāng)屬性被訪問時觸發(fā),用于收集依賴(如將當(dāng)前組件的 Watcher 添加到 Dep 依賴收集器)。
  • set 攔截:當(dāng)屬性被修改時觸發(fā),用于通知依賴更新(調(diào)用 Dep 的 notify 方法,觸發(fā)所有相關(guān) Watcher 重新執(zhí)行)
2.1、關(guān)鍵限制與解決方案
  1. 無法監(jiān)聽新增/刪除屬性
    Object.defineProperty 僅能劫持初始化時存在的屬性,新增屬性(如 this.obj.newProp = 1)或刪除屬性(如 delete this.obj.prop)不會觸發(fā)響應(yīng)式更新。需通過 Vue.set(obj, key, value) 或 this.$delete(obj, key) 手動處理:

    • Vue.set 原理:對對象調(diào)用 defineReactive 添加 getter/setter,并觸發(fā) dep.notify()
  2. 數(shù)組響應(yīng)式的特殊處理
    由于直接監(jiān)聽數(shù)組索引性能開銷大,Vue 2 采用重寫數(shù)組原型方法(push/pop/splice 等 7 個變異方法)的方式實現(xiàn)數(shù)組響應(yīng)式:

    • 攔截數(shù)組方法調(diào)用,執(zhí)行原生邏輯后觸發(fā) dep.notify(),并對新增元素遞歸執(zhí)行響應(yīng)式處理。
    • 直接修改索引(如 arr[0] = 1)或長度(如 arr.length = 0)無法觸發(fā)更新,需使用 Vue.set(arr, index, value)。
  3. 深層嵌套對象的性能問題
    初始化時需遞歸遍歷所有嵌套屬性,為每個屬性添加 getter/setter,當(dāng)數(shù)據(jù)層級過深(如 10 層以上)時,會導(dǎo)致初始化性能下降

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容