Vue.js響應(yīng)式數(shù)據(jù)的簡單實現(xiàn)方法(一看就會)
引言
在Vue.js之中,Vue會自動跟蹤JavaScript狀態(tài)變化并在狀態(tài)發(fā)生改變時響應(yīng)式地更新DOM,這就是Vue.js的兩大核心功能之一——響應(yīng)性,是每一個Vue.js框架使用者必須熟練掌握的的功能。而得益于Vue.js自身支持的聲明式渲染,Vue.js的學(xué)習(xí)成本大大降低,就算是一個前端領(lǐng)域的小白,只要能看懂并簡單使用基本的HTML、JavaScript以及CSS,就能夠很快上手Vue.js。學(xué),確實好學(xué);用,真的好用!但,你對Vue.js框架的內(nèi)部實現(xiàn)原理掌握多少呢?今天,就讓我們一起來簡單復(fù)現(xiàn)一下Vue.js數(shù)據(jù)響應(yīng)式。
基本概念
副作用函數(shù)
什么是副作用函數(shù)?意如其名,副作用函數(shù)指的就是會產(chǎn)生副作用的函數(shù)。什么是副作用呢?就是會對函數(shù)作用域外的其他部分產(chǎn)生影響。俗話說:是藥三分毒,能治病,亦能致病。藥,就有副作用,副作用函數(shù)也是。
副作用函數(shù)代碼示例如下:
當(dāng)effect函數(shù)執(zhí)行時,它會設(shè)置body的文本內(nèi)容,從而直接或間接影響到其他任何對body文本內(nèi)容有所依賴的函數(shù)的執(zhí)行。這就是一個簡單的副作用函數(shù)。
響應(yīng)式數(shù)據(jù)
以我的理解,相較“響應(yīng)式數(shù)據(jù)”而言更直白的叫法應(yīng)該是“副作用數(shù)據(jù)”,就好像副作用函數(shù)的執(zhí)行可能會影響到函數(shù)作用域外的其他內(nèi)容一樣,“副作用數(shù)據(jù)”的更改可能會直接或間接影響到所有依賴該數(shù)據(jù)的函數(shù)。
假響應(yīng)式數(shù)據(jù)代碼示例如下:
如上圖,假設(shè)每一次修改對象obj的text屬性值,都會觸發(fā)函數(shù)effect的重新執(zhí)行,那么就可以說對象obj是一個響應(yīng)式數(shù)據(jù)。當(dāng)然,在這個示例里,實際上并沒有實現(xiàn)對obj對象的數(shù)據(jù)響應(yīng)。
響應(yīng)式數(shù)據(jù)的基本實現(xiàn)
實現(xiàn)思路
仔細觀察思考上述的例子,你可能會發(fā)現(xiàn)響應(yīng)式數(shù)據(jù)的實現(xiàn)存在兩個關(guān)鍵點:
- 副作用函數(shù)effect的執(zhí)行會觸發(fā)字段obj.text的讀取操作
- 響應(yīng)式數(shù)據(jù)obj.text值的修改會觸發(fā)字段obj.text的設(shè)置操作
事情的脈絡(luò)漸漸清晰起來:如果我們能夠攔截對象obj的讀取和設(shè)置操作,在副作用函數(shù)effect首次讀取字段obj.text的值時將它與對象obj關(guān)聯(lián)起來,此后每次重新設(shè)置字段obj.text的值,都會重新調(diào)用一次effect函數(shù),這樣不就簡單的實現(xiàn)了對obj對象的響應(yīng)嗎?
初步實現(xiàn)嘗試
實現(xiàn)的思路有了,那現(xiàn)在最關(guān)鍵的問題就是:如何實現(xiàn)攔截一個對象屬性的讀取和設(shè)置操作。如果你對JavaScript足夠熟悉,你可能就會想到Object.defineProperty函數(shù)以及Proxy對象代理。是的,這兩種方案都可以實現(xiàn)攔截一個對象屬性的讀取以及設(shè)置操作。事實上,用Object.defineProperty函數(shù)實現(xiàn)數(shù)據(jù)響應(yīng)正是Vue.js 2中所采用的方法,而Proxy對象代理則正是Vue.js 3中所采用的方法。
接下來讓我們順著上面的思路采用proxy實現(xiàn)一下:
這就是采用Proxy代理對象簡單實現(xiàn)的數(shù)據(jù)響應(yīng)式,你完全可以自行創(chuàng)建一個副作用函數(shù)effect進行測試。當(dāng)然,考慮到復(fù)雜多變的環(huán)境,此時的數(shù)據(jù)相應(yīng)式還有很多繼續(xù)完善的地方,讓我們再加加班,盡可能地給出一個相對完美的響應(yīng)式數(shù)據(jù)實現(xiàn)方案。
完善響應(yīng)系統(tǒng)
泛化副作用函數(shù)名
假如有一天,副作用的函數(shù)名不叫effect了。而是叫effect1或者effect2,甚至副作用函數(shù)沒有直白的名字了,變成了一個匿名函數(shù),那么上述的響應(yīng)系統(tǒng)方案顯然是行不通的。此時,為了滿足需求,我們需要提供一個用來注冊副作用函數(shù)的機制,達到泛化副作用函數(shù)名的效果。
注冊副作用函數(shù)名的代碼示例如下:
這樣,即使是一個匿名函數(shù),也能夠被成功地注冊為副作用函數(shù),注冊方法如下:
當(dāng)然,此時攔截數(shù)據(jù)的讀取操作也需要做細微的調(diào)整:
修復(fù)漏洞
在很多時候,debug都是最頭疼的,特別是明明知道有bug,但就是找不到修復(fù)的方案,那種感覺真的像在坐牢……
現(xiàn)在我們來考慮一個極端條件:假如,在響應(yīng)式數(shù)據(jù)對象obj上添加了一個原本不存在的屬性,那么會發(fā)生什么?如果你對前面的內(nèi)容還不熟悉,可以再返回去翻翻代碼。你會發(fā)現(xiàn)一個驚人的事實:在響應(yīng)式數(shù)據(jù)對象obj上添加一個原本不存在的屬性,會在這個新添加的屬性與相關(guān)的副作用函數(shù)之間建立響應(yīng)聯(lián)系。冷靜下來思考一下,其實,導(dǎo)致該問題出現(xiàn)的根本原因是,沒有在副作用函數(shù)與被操作的目標(biāo)字段之間建立明確的聯(lián)系。那,該如何解決呢?
你想想,在數(shù)據(jù)結(jié)構(gòu)中存不存在一種結(jié)構(gòu),它具有一一對應(yīng)的關(guān)系?有,當(dāng)然有,映射就是。順著這個思路,那我們可不可以用映射的來建立目標(biāo)字段與副作用函數(shù)key-value對應(yīng)的關(guān)系?當(dāng)然可以!那么我們就可以先把負責(zé)儲存函數(shù)的變量bucket聲明為一個映射Map<target, Map<key, Set()>>用來儲存響應(yīng)式數(shù)據(jù)(key)-該響應(yīng)式數(shù)據(jù)所有屬性相關(guān)的副作用函數(shù)(value),其中,Map<key, Set>儲存的就是響應(yīng)式對象屬性與相應(yīng)的副作用函數(shù)集,這樣,一個明確的聯(lián)系就建立起來了。而在著手優(yōu)化響應(yīng)代碼之前,我們再想一想:bucket用WeakMap會不會比用Map要更好一點?我實話直說吧,當(dāng)然應(yīng)該用WeakMap,因為WeakMap的key是弱引用,不會影響到垃圾回收器的工作,會在合適的時候被回收,用在這里更合適。
具體實現(xiàn)代碼如下:
總結(jié)
總的來說,要想實現(xiàn)一個響應(yīng)式數(shù)據(jù)其實就是利用Proxy對象代理或者Object.defineProperty對象來攔截對數(shù)據(jù)的讀取和設(shè)置操作并與相應(yīng)的副作用函數(shù)作精確綁定。那么,如果現(xiàn)在要求你用Object.defineProperty對象來實現(xiàn)數(shù)據(jù)響應(yīng),你能夠獨立實現(xiàn)了嗎?試一下唄!
到此這篇關(guān)于Vue.js響應(yīng)式數(shù)據(jù)的簡單實現(xiàn)方法的文章就介紹到這了,更多相關(guān)Vue.js響應(yīng)式數(shù)據(jù)的實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Vue中echarts響應(yīng)式頁面變化resize()的用法介紹
Vue項目中開發(fā)數(shù)據(jù)大屏,使用echarts圖表根據(jù)不同尺寸的屏幕進行適配,resize()可以調(diào)用echarts中內(nèi)置的resize函數(shù)進行自適應(yīng)縮放,本文將給大家詳細介紹resize()的用法,需要的朋友可以參考下2023-06-06Vue項目自動轉(zhuǎn)換 px 為 rem的實現(xiàn)方法
這篇文章主要介紹了Vue項目自動轉(zhuǎn)換 px 為 rem的實現(xiàn)方法,本文是通過一系列的配置后,轉(zhuǎn)換成熱門,具體內(nèi)容詳情大家跟隨小編一起通過本文學(xué)習(xí)吧2018-10-10Vue-admin-template?添加、跳轉(zhuǎn)子頁面問題
這篇文章主要介紹了Vue-admin-template?添加、跳轉(zhuǎn)子頁面問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10vue使用map代替Aarry數(shù)組循環(huán)遍歷的方法
這篇文章主要介紹了vue使用map代替Aarry數(shù)組循環(huán)遍歷的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04