vue2的响应式原理学“废”了吗?继续观摩vue3响应式原理Proxy
一文了解Vue3的響應(yīng)式原理
- 一、🟩回顧Object.defineProperty
- 二、🟨Proxy基本使用
- 三、🟦學(xué)習(xí)Proxy語法:Reflect
- 四、🟧Vue3如何用Proxy實(shí)現(xiàn)響應(yīng)式
- 1、實(shí)現(xiàn)響應(yīng)式
- 2、Proxy總結(jié)
- (1)深度監(jiān)聽,性能更好
- (2)可監(jiān)聽 新增/刪除 屬性
- (3)可監(jiān)聽數(shù)組變化
- 3、兩者對(duì)比
- 五、🟪結(jié)束語
之前寫過一篇文章談?wù)?vue2.x 的響應(yīng)式原理,但因?yàn)?vue3 也來了,緊跟著 vue3 的步伐,周一開始學(xué)起了 vue3 的響應(yīng)式原理。
大家應(yīng)該都聽過, vue3 用 proxy 來解決響應(yīng)式原理,同時(shí)它解決了 vue2 中 Object.definePropery 存在的一些問題,但同時(shí)也帶來了一些問題。
在下面的這篇文章中,將講解關(guān)于 vue3 用 proxy 如何實(shí)現(xiàn)響應(yīng)式,以及帶來的一些問題。一起來學(xué)習(xí)吧💯
一、🟩回顧Object.defineProperty
這里需要大家對(duì) ObjectProperty 的知識(shí)點(diǎn)有一個(gè)預(yù)先了解,如有需要了解可點(diǎn)擊文章進(jìn)行查看~
現(xiàn)在,我們來回顧下 Object.defineProperty 的缺點(diǎn):
- 深度監(jiān)聽時(shí)需要一次性遞歸;
- 無法監(jiān)聽新增屬性/刪除屬性(需要配合 Vue.set 或 Vue.delete 使用);
- 無法原生監(jiān)聽數(shù)組,需要特殊處理。
帶著 Object.defineProperty 的這幾個(gè)缺點(diǎn),接下來我們開始進(jìn)入 Proxy 的世界。
二、🟨Proxy基本使用
下面用一段代碼來演示 Proxy 的基本使用。具體代碼如下:
const data = {name: 'monday',age:18 } //const data = ['a', 'b', 'c']const proxyData = new Proxy(data, {get(target, key, receiver){//只處理本身(非原型的)屬性const ownKeys = Reflect.ownKeys(target)if(oenKeys.includes(key)){console.log('get', key) //監(jiān)聽}const result = Reflect.get(target, key, receiver)return result // 返回結(jié)果},set(target, key, val, receiver){//重復(fù)的數(shù)據(jù),不處理if(val === target[key]){return true}const result = Reflect.set(target, key, val, receiver)console.log('set', key, val)//console.log('result', result) //truereturn result // 是否設(shè)置成功},deleteProperty(target, key){const result = Reflect.deleteProperty(target, key)console.log('delete property', key)return result // 是否刪除成功} })通過以上代碼可得,我們先定義一個(gè)對(duì)象字面量的 data ,之后在作為 Proxy 實(shí)例化的參數(shù)進(jìn)行傳遞。且 proxyData 實(shí)現(xiàn)了 get 、 set 和 deleteProperty 的方法,可以對(duì)數(shù)據(jù)進(jìn)行增刪改操作。
三、🟦學(xué)習(xí)Proxy語法:Reflect
我們?cè)賮碚J(rèn)識(shí) Proxy 的一個(gè)好朋友,Reflect。
Reflect 對(duì)象有著和 Proxy 一一對(duì)應(yīng)的能力,Reflect對(duì)象一共有 13 個(gè)靜態(tài)方法,這也就是我們平常所聽到的 proxy 有多達(dá)13種攔截行為,而 Reflect 的這13種靜態(tài)方法匹配的就是 Proxy 的13種攔截行為 。
| Reflect.get(target, name, receiver) |
| Reflect.set(target, name, value, receiver) |
| Reflect.has(obj, name) |
| Reflect.deleteProperty(obj, name) |
| Reflect.construct(target, args) |
| Reflect.getPrototypeOf(obj) |
| Reflect.setPrototypeOf(obj, newProto) |
| Reflect.apply(func, thisArg, args) |
| Reflect.defineProperty(target, propertyKey, attribute) |
| Reflect.getOwnPropertyDescriptor(target, propertyKey) |
| Reflect.isExtensible(target) |
| Reflect.preventExtensions(target) |
| Reflect.ownKeys(target) |
Reflect 的出現(xiàn)是為了替換掉 Object 上的工具函數(shù),這里不做具體介紹,詳情可查看文檔 。
四、🟧Vue3如何用Proxy實(shí)現(xiàn)響應(yīng)式
1、實(shí)現(xiàn)響應(yīng)式
下面來實(shí)現(xiàn)Proxy的響應(yīng)式。附上代碼:
// 創(chuàng)建響應(yīng)式 function reactive(target = {}) {if (typeof target !== 'object' || target == null) {// 不是對(duì)象或數(shù)組,則返回return target}// 代理配置const proxyConf = {get(target, key, receiver) {// 只處理本身(非原型的)屬性const ownKeys = Reflect.ownKeys(target)if (ownKeys.includes(key)) {console.log('get', key) // 監(jiān)聽}const result = Reflect.get(target, key, receiver)// 深度監(jiān)聽return reactive(result)},set(target, key, val, receiver) {// 重復(fù)的數(shù)據(jù),不處理if (val === target[key]) {return true}const ownKeys = Reflect.ownKeys(target)// 判斷是已有屬性還是新增屬性if (ownKeys.includes(key)) {console.log('已有的 key', key)} else {console.log('新增的 key', key)} const result = Reflect.set(target, key, val, receiver)console.log('set', key, val)// console.log('result', result) // truereturn result // 是否設(shè)置成功},deleteProperty(target, key) {const result = Reflect.deleteProperty(target, key)console.log('delete property', key)// console.log('result', result) // truereturn result // 是否刪除成功}}// 生成代理對(duì)象const observed = new Proxy(target, proxyConf)return observed }// 測(cè)試數(shù)據(jù) const data = {name: 'monday',age: 18,info: {city: 'FuZhou',a: {b: {c: {d: {e: 100}}}}} }const proxyData = reactive(data)我們?cè)诳刂婆_(tái)來驗(yàn)證數(shù)據(jù):
從上圖中可以看到,用 proxy 來實(shí)現(xiàn)響應(yīng)式,如果遇到需要深度遞歸的數(shù)組時(shí),它不會(huì)像 defineProperty 那樣深度遞歸,它會(huì)在什么時(shí)候 get ,什么時(shí)候再深度遞歸。本質(zhì)上來講就是,你獲取到哪一層,那一層才會(huì)觸發(fā)響應(yīng)式。你獲取不到的深層,它就不會(huì)觸發(fā)響應(yīng)式。且從代碼中我們可以了解到, Proxy 在修改屬性時(shí),如果數(shù)據(jù)是重復(fù)的,則不進(jìn)行處理。如果數(shù)據(jù)不重復(fù),再進(jìn)行處理。這樣一來,就極大程度上提高了軟件的性能。
2、Proxy總結(jié)
現(xiàn)在來對(duì)上述Proxy的內(nèi)容做一個(gè)總結(jié):
(1)深度監(jiān)聽,性能更好
defineProperty 是一次性遞歸完成;而 Proxy 是什么時(shí)候 get ,什么時(shí)候再深度遞歸。
(2)可監(jiān)聽 新增/刪除 屬性
在 vue2 中, defineProperty 是無法新增/刪除屬性的,需要配合 Vue.set 和 Vue.delete 來使用,而在 Vue3 中, Proxy 可以新增和刪除屬性,無需進(jìn)行特殊處理。
(3)可監(jiān)聽數(shù)組變化
在 vue2 中,監(jiān)聽數(shù)組變化是需要進(jìn)行特殊處理,且只能一次性深度遞歸完成。而在 vue3 中,可以監(jiān)聽數(shù)組變化,并且是什么時(shí)候get什么時(shí)候再遞歸,獲取不到的深層,不會(huì)觸發(fā)響應(yīng)式。
3、兩者對(duì)比
講到這里,我們?cè)侔?vue2 中的 Object.defineProperty 和 vue3 中的 Proxy 做一個(gè)對(duì)比:
- Proxy 能良好的規(guī)避 Object.defineProperty 的問題;
- Proxy 無法兼容所有瀏覽器(如 IE11 ),且無法 polyfill 。
五、🟪結(jié)束語
從某種程度上來說, vue3 的 Proxy 確實(shí)帶來了一些好處,但同時(shí)也帶來了一些問題。正因?yàn)槿绱?#xff0c; vue2 的 Object.defineProperty 還會(huì)存在很長(zhǎng)一段時(shí)間。所以,新技術(shù)的使用總會(huì)經(jīng)過一個(gè)從試用階段到穩(wěn)定階段的過程。
關(guān)于vue3的響應(yīng)式原理講到這里就結(jié)束啦!如有疑問或文章有誤歡迎評(píng)論區(qū)留言或私信交流~
- 關(guān)注公眾號(hào) 星期一研究室 ,第一時(shí)間關(guān)注技術(shù)干貨,更多有趣的專欄待你解鎖~
- 如果這篇文章對(duì)你有用,記得 一鍵三連 再走哦!
- 我們下期見!🥂🥂🥂
總結(jié)
以上是生活随笔為你收集整理的vue2的响应式原理学“废”了吗?继续观摩vue3响应式原理Proxy的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 与高通、虹软深度合作 真我GT5 Pro
- 下一篇: 模块化妙用!用vue3实现一个鼠标追踪器