VUE2—defineProperty和VUE3—proxy使用方式
前言
使用過vue開發(fā)的盆友都知道Vue2和Vue3的響應(yīng)式原理是不一樣的,vue2用的是Object.defineProperty,vue3用的是proxy。那他們具體是什么呢?又有什么區(qū)別呢?
下面叫我簡單做個筆記。有什么錯誤望各位大佬不吝指點。
什么是Object.defineProperty()
Object.defineProperty是 es5 引入的一個方法,用于定義或修改對象的屬性的方法,可以控制屬性的特性(如可枚舉性、可配置性、可寫性等)。
Object.defineProperty()語法
Object.defineProperty(obj, prop, descriptor)
參數(shù)說明:
obj:定義屬性的對象。prop:定義或修改的屬性的名稱。descriptor:屬性的描述符對象,包含屬性的特性設(shè)置。
descriptor 對象下包含的屬性:
value:屬性的值。writable:屬性是否可寫,即是否可以使用賦值操作符改變屬性值。configurable:屬性描述符是否可以被改變,或者屬性是否可以被刪除,默認(rèn)為false。enumerable:屬性是否可枚舉,即是否會出現(xiàn)在使用 for...in 循環(huán)時。get:一個函數(shù),當(dāng)屬性被讀取時調(diào)用,返回屬性值。set:一個函數(shù),當(dāng)屬性被賦值時調(diào)用,接收新值作為參數(shù)。
<script>
// 定義一個對象名為(person)的對象【對象的屬性有(name、sex)】
let person = { name: '小明', sex: '男'}
//給對象(person)添加一個屬性名為(age)的屬性,屬性描述符只包含了 value 屬性,表示 age 屬性的初始值。
Object.defineProperty(person, 'age', {
value: 18, // 屬性的值
enumerable: true, // 屬性是否可枚舉
writable: true, // 屬性是否可寫/可修改
configurable: true // 屬性是否可以被刪除
})
console.log(person);
</script>proxy簡介
Proxy是ES6中的一種用于創(chuàng)建代理對象的特殊對象。它允許我們定義自定義行為,例如攔截和修改對象的默認(rèn)操作。Proxy可以用于攔截對象的各種操作,包括屬性訪問、賦值、函數(shù)調(diào)用等。
Proxy的構(gòu)造函數(shù)接受兩個參數(shù):目標(biāo)對象(被代理的對象)和一個處理器對象(用于定義攔截器)
常用的攔截方法包括:get、set、apply、construct、deleteProperty、has、getOwnPropertyDescriptor等?!?strong>這些攔截方法會在代理對象進(jìn)行對應(yīng)操作時自動觸發(fā)】
注:Proxy詳解見我另一篇文章: ES6之---Proxy簡介 這里就不過多敘述了
// 寫法:target是目標(biāo)對象,handler是處理器對象
const proxy = new Proxy(target, handler);
簡單示例
let star = {
name: '小明',
age: 18
}
let proxy = new Proxy(star,{
get(targetObj, propoty, receiver) {
console.log(`我是被代理的對象${targetObj}`)
console.log(`我是你訪問的被代理的屬性${propoty}`)
//receiver是代理對象proxy
return targetObj[propoty]
}
})vue中defineProperty和proxy對比
1.監(jiān)聽數(shù)據(jù)的角度
defineproperty只能監(jiān)聽某個屬性而不能監(jiān)聽整個對象。proxy不用設(shè)置具體屬性,直接監(jiān)聽整個對象。defineproperty監(jiān)聽需要知道是哪個對象的哪個屬性,而proxy只需要知道哪個對象就可以了。也就是會省去for in循環(huán)提高了效率。- Object.defineProperty有一個致命的缺點,就是無法監(jiān)聽對象屬性的新增和刪除;可以使用this.$set和this.$delete解決,這個方法在項目中也經(jīng)常使用
2.監(jiān)聽對原對象的影響
- 因為
defineproperty是通過在原對象身上新增或修改屬性增加描述符的方式實現(xiàn)的監(jiān)聽效果,一定會修改原數(shù)據(jù)。 - 而
proxy只是原對象的代理,proxy會返回一個代理對象不會在原對象上進(jìn)行改動,對原數(shù)據(jù)無污染。
3.實現(xiàn)對數(shù)組的監(jiān)聽
- 因為數(shù)組
length的特殊性 (length 的描述符configurable 和 enumerable 為 false,并且妄圖修改 configurable 為 True 的話 js 會直接報錯:VM305:1 Uncaught TypeError: Cannot redefine property: length) defineproperty無法監(jiān)聽數(shù)組長度變化,Vue只能通過重寫數(shù)組方法的方式變現(xiàn)達(dá)成監(jiān)聽的效果,光重寫數(shù)組方法還是不能解決修改數(shù)組下標(biāo)時監(jiān)聽的問題,只能再使用自定義的$set的方式- 而
proxy因為自身特性,是創(chuàng)建新的代理對象而不是在原數(shù)據(jù)身上監(jiān)聽屬性,對代理對象進(jìn)行操作時,所有的操作都會被捕捉,包括數(shù)組的方法和length操作,再不需要重寫數(shù)組方法和自定義set函數(shù)了。(代碼示例在下方)
4. 監(jiān)聽的范圍
defineproperty只能監(jiān)聽到value的get set變化。proxy可以監(jiān)聽除[[getOwnPropertyNames]]以外所有JS的對象操作。(鏈接看下方)監(jiān)聽的范圍更大更全面。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于vue-cli配置lib-flexible + rem實現(xiàn)移動端自適應(yīng)
這篇文章主要介紹了基于vue-cli配置lib-flexible + rem實現(xiàn)移動端自適應(yīng),需要的朋友可以參考下2017-12-12

