小編給大家分享一下Vue.js響應式數據如何實現,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
什么是副作用函數?意如其名,副作用函數指的就是會產生副作用的函數。什么是副作用呢?就是會對函數作用域外的其他部分產生影響。俗話說:是藥三分毒,能治病,亦能致病。藥,就有副作用,副作用函數也是。
副作用函數代碼示例如下:

當effect函數執行時,它會設置body的文本內容,從而直接或間接影響到其他任何對body文本內容有所依賴的函數的執行。這就是一個簡單的副作用函數。
以我的理解,相較“響應式數據”而言更直白的叫法應該是“副作用數據”,就好像副作用函數的執行可能會影響到函數作用域外的其他內容一樣,“副作用數據”的更改可能會直接或間接影響到所有依賴該數據的函數。
假響應式數據代碼示例如下:

如上圖,假設每一次修改對象obj的text屬性值,都會觸發函數effect的重新執行,那么就可以說對象obj是一個響應式數據。當然,在這個示例里,實際上并沒有實現對obj對象的數據響應。
仔細觀察思考上述的例子,你可能會發現響應式數據的實現存在兩個關鍵點:
副作用函數effect的執行會觸發字段obj.text的讀取操作
響應式數據obj.text值的修改會觸發字段obj.text的設置操作
事情的脈絡漸漸清晰起來:如果我們能夠攔截對象obj的讀取和設置操作,在副作用函數effect首次讀取字段obj.text的值時將它與對象obj關聯起來,此后每次重新設置字段obj.text的值,都會重新調用一次effect函數,這樣不就簡單的實現了對obj對象的響應嗎?
實現的思路有了,那現在最關鍵的問題就是:如何實現攔截一個對象屬性的讀取和設置操作。如果你對JavaScript足夠熟悉,你可能就會想到Object.defineProperty函數以及Proxy對象代理。是的,這兩種方案都可以實現攔截一個對象屬性的讀取以及設置操作。事實上,用Object.defineProperty函數實現數據響應正是Vue.js 2中所采用的方法,而Proxy對象代理則正是Vue.js 3中所采用的方法。
接下來讓我們順著上面的思路采用proxy實現一下:

這就是采用Proxy代理對象簡單實現的數據響應式,你完全可以自行創建一個副作用函數effect進行測試。當然,考慮到復雜多變的環境,此時的數據相應式還有很多繼續完善的地方,讓我們再加加班,盡可能地給出一個相對完美的響應式數據實現方案。
假如有一天,副作用的函數名不叫effect了。而是叫effect1或者effect2,甚至副作用函數沒有直白的名字了,變成了一個匿名函數,那么上述的響應系統方案顯然是行不通的。此時,為了滿足需求,我們需要提供一個用來注冊副作用函數的機制,達到泛化副作用函數名的效果。
注冊副作用函數名的代碼示例如下:

這樣,即使是一個匿名函數,也能夠被成功地注冊為副作用函數,注冊方法如下:

當然,此時攔截數據的讀取操作也需要做細微的調整:

在很多時候,debug都是最頭疼的,特別是明明知道有bug,但就是找不到修復的方案,那種感覺真的像在坐牢……
現在我們來考慮一個極端條件:假如,在響應式數據對象obj上添加了一個原本不存在的屬性,那么會發生什么?如果你對前面的內容還不熟悉,可以再返回去翻翻代碼。你會發現一個驚人的事實:在響應式數據對象obj上添加一個原本不存在的屬性,會在這個新添加的屬性與相關的副作用函數之間建立響應聯系。冷靜下來思考一下,其實,導致該問題出現的根本原因是,沒有在副作用函數與被操作的目標字段之間建立明確的聯系。那,該如何解決呢?
你想想,在數據結構中存不存在一種結構,它具有一一對應的關系?有,當然有,映射就是。順著這個思路,那我們可不可以用映射的來建立目標字段與副作用函數key-value對應的關系?當然可以!那么我們就可以先把負責儲存函數的變量bucket聲明為一個映射Map<target, Map<key, Set()>>用來儲存響應式數據(key)-該響應式數據所有屬性相關的副作用函數(value),其中,Map<key, Set>儲存的就是響應式對象屬性與相應的副作用函數集,這樣,一個明確的聯系就建立起來了。而在著手優化響應代碼之前,我們再想一想:bucket用WeakMap會不會比用Map要更好一點?我實話直說吧,當然應該用WeakMap,因為WeakMap的key是弱引用,不會影響到垃圾回收器的工作,會在合適的時候被回收,用在這里更合適。
具體實現代碼如下:

以上是“Vue.js響應式數據如何實現”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。