defineProperty 和 Proxy區別(直接上結論有一句廢話你打我)

海洋餅乾發表於2021-12-13

在Vue2和3 中 defineProperty 和 Proxy 都是用來實現響應式資料繫結的。實現的功能類似,但是兩個API卻有著本質的區別。

  1. 監聽資料的角度

    1. defineproperty只能監聽某個屬性而不能監聽整個物件。
    2. proxy不用設定具體屬性,直接監聽整個物件。
    3. defineproperty監聽需要知道是哪個物件的哪個屬性,而proxy只需要知道哪個物件就可以了。也就是會省去for in迴圈提高了效率。
  2. 監聽對原物件的影響

    1. 因為defineproperty是通過在原物件身上新增或修改屬性增加描述符的方式實現的監聽效果,一定會修改原資料。
    2. proxy只是原物件的代理,proxy會返回一個代理物件不會在原物件上進行改動,對原資料無汙染。
  3. 實現對陣列的監聽

    1. 因為陣列 length 的特殊性 (length 的描述符configurable 和 enumerable 為 false,並且妄圖修改 configurable 為 True 的話 js 會直接報錯:VM305:1 Uncaught TypeError: Cannot redefine property: length)
    2. defineproperty無法監聽陣列長度變化, Vue只能通過重寫陣列方法的方式變現達成監聽的效果,光重寫陣列方法還是不能解決修改陣列下標時監聽的問題,只能再使用自定義的$set的方式
    3. proxy因為自身特性,是建立新的代理物件而不是在原資料身上監聽屬性,對代理物件進行操作時,所有的操作都會被捕捉,包括陣列的方法和length操作,再不需要重寫陣列方法和自定義set函式了。(程式碼示例在下方)

    4. 監聽的範圍

    1. defineproperty只能監聽到valueget set 變化。
    2. proxy可以監聽除 [[getOwnPropertyNames]] 以外所有JS的物件操作。(連結看下方)監聽的範圍更大更全面。

點選檢視proxy支援監聽的物件操作方法(除getOwnPropertyNames)

Proxy監聽陣列變化示例:

let array = ['1', '2']
let arrayProxy = new Proxy(array, {
    get(target, key) {
        console.log('(key:', key + ") 發生了get操作")
        return target[key]
    },
    set(target, key, value) {
        console.log('(key:', key + ") 發生了set操作, value= " + value)
        return target[key] = value
    }
})
arrayProxy.push('我是push函式push到陣列中的值')

// (key: push) 發生了get操作
// (key: length) 發生了get操作
// (key: 2) 發生了set操作, value= 我是push函式push到陣列中的值
// (key: length) 發生了set操作, value= 3

// 從log可以看出push length等操作都被捕捉了

相關文章