在Vue2和3 中 defineProperty 和 Proxy 都是用來實現響應式資料繫結的。實現的功能類似,但是兩個API卻有著本質的區別。
監聽資料的角度
defineproperty
只能監聽某個屬性而不能監聽整個物件。proxy
不用設定具體屬性,直接監聽整個物件。defineproperty
監聽需要知道是哪個物件的哪個屬性,而proxy
只需要知道哪個物件就可以了。也就是會省去for in
迴圈提高了效率。監聽對原物件的影響
- 因為
defineproperty
是通過在原物件身上新增或修改屬性增加描述符的方式實現的監聽效果,一定會修改原資料。- 而
proxy
只是原物件的代理,proxy
會返回一個代理物件不會在原物件上進行改動,對原資料無汙染。實現對陣列的監聽
- 因為陣列
length
的特殊性(length 的描述符configurable 和 enumerable 為 false,並且妄圖修改 configurable 為 True 的話 js 會直接報錯:VM305:1 Uncaught TypeError: Cannot redefine property: length)
defineproperty
無法監聽陣列長度變化,Vue
只能通過重寫陣列方法的方式變現達成監聽的效果,光重寫陣列方法還是不能解決修改陣列下標時監聽的問題,只能再使用自定義的$set
的方式- 而
proxy
因為自身特性,是建立新的代理物件而不是在原資料身上監聽屬性,對代理物件進行操作時,所有的操作都會被捕捉,包括陣列的方法和length
操作,再不需要重寫陣列方法和自定義set
函式了。(程式碼示例在下方)4. 監聽的範圍
defineproperty
只能監聽到value
的get set
變化。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等操作都被捕捉了