日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于Object.defineProperty实现双向数据绑定

發(fā)布時間:2025/3/19 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于Object.defineProperty实现双向数据绑定 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

雙向數(shù)據(jù)綁定可算是前端領(lǐng)域經(jīng)久不衰的熱詞,不管是前端開發(fā)還是面試都會有所涉及。而且不同的框架也想盡一切辦法去實現(xiàn)這一特性,比如:
Knockout / Backbone --- 發(fā)布-訂閱模式
Angular --- ‘臟檢查’
Vue --- 'Object.defineProperty'

那么雙向數(shù)據(jù)綁定到底是什么?沒圖說個卵,直接上圖

簡單的說就是在數(shù)據(jù)和UI之間建立雙向的通信通道,當(dāng)用戶通過Function改變了數(shù)據(jù),那么這個改變也會立即反應(yīng)到UI上;或者說用戶通過UI的操作,那么這些操作也會隨之引起對應(yīng)的數(shù)據(jù)變動。emmmmmm...沒毛病!

既然本文標(biāo)題是討論Object.defineProperty,那么筆者就把當(dāng)前火熱的到Boom的國產(chǎn)框架:Vue.js 請出來,然后在了解完她實現(xiàn)雙向數(shù)據(jù)綁定的原理之后,我們著手實現(xiàn)一個抽象派的雙向數(shù)據(jù)綁定。那么那位朋友就說了,什么叫 抽象派 ?我估計吧,可能就是馬(Vue)和馬骨架的區(qū)別吧,TAT...

在介紹Vue的雙向數(shù)據(jù)綁定之前,筆者還想多叨叨幾句,如果某一天有人問你:Vue是如何實現(xiàn)雙向數(shù)據(jù)綁定的? 姑且先在這里停頓下,思考下這個問題的答案...................
或許有朋友會脫口而出“數(shù)據(jù)劫持”,說的沒錯!的確就是“數(shù)據(jù)劫持”,但是還不夠充分和不夠精確。筆者在這里也談下自己的一點點所見所聞所想:

  • 不夠精確:與其說是 數(shù)據(jù)劫持,更應(yīng)該說是對數(shù)據(jù)對象的Setter和Getter實現(xiàn)的劫持。
  • 不夠充分:為什么說不夠充分?是因為 Object.defineProperty 僅僅是實現(xiàn)了對數(shù)據(jù)的監(jiān)控,后續(xù)實現(xiàn)對UI的重新渲染并不是它做的,所以這里還涉及到 發(fā)布-訂閱模式(有興趣的朋友戳這里);過程是,當(dāng)監(jiān)控的數(shù)據(jù)對象被更改后,這個變更會被廣播給所有訂閱該數(shù)據(jù)的watcher,然后由該 watcher實現(xiàn)對頁面的重新渲染。
  • 下面進(jìn)入正題,一起了解下Vue實現(xiàn)雙向數(shù)據(jù)綁定的原理,果斷上圖:

    首先,Vue的Compile模塊會對Vue的 template 代碼進(jìn)行編譯解析并生成一系列的watcher,也可以稱之為“更新函數(shù)”,它負(fù)責(zé)把變更后的相關(guān)數(shù)據(jù)重新渲染到指定的地方。舉個栗子:

    <input v-model="message">

    Compile會解析出 v-moel 這個指令并且生成 watcher 并連接數(shù)據(jù)中的 message 和當(dāng)前這個Dom對象,一旦收到這個message被變更的通知,watcher就會根據(jù)變更對這個Dom進(jìn)行重新渲染。

    當(dāng)然一個頁面或者一個項目中肯定有很多watcher,因此Vue使用了Dep這個對象來存儲每一個watcher,當(dāng)數(shù)據(jù)發(fā)生變更,Observer會調(diào)用Dep的notify方法以通知所有訂閱了該數(shù)據(jù)的watcher,讓它們醒醒該干活了...

    Vue的雙向數(shù)據(jù)綁定也說得差不多了,下面就開始順著這個思路著手寫一個吧,畢竟說得多不如code來得好啊!!!具體的實現(xiàn)效果如下,Let‘s do it

    不知道為什么GIF上傳不了,所以只能將就用圖片了,QAQ....

    功能就用文字解釋下:
    第一個行的 title 0 直接顯示的是數(shù)據(jù),以便觀察;我們可以在輸入框中輸入任何int, 然后點擊“加”可以實現(xiàn)對數(shù)值的 +1 操作,同時輸入框的數(shù)值和 title 也會隨之變化;當(dāng)然,通過輸入數(shù)值,title也會跟著變化。

    首先把Html代碼呈上來:

    <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Object.defineProperty實現(xiàn)雙向綁定</title> </head><body><h1 id='h1'></h1><input type="text" id="inp" onkeyup="inputChange(event)"><input type="button" value="加" onclick="btnAdd()" /> </body> <script src="./index.js"></script></html>

    然后開始一步一步在index.js里寫代碼吧
    1) 首先我們先定義一個數(shù)據(jù)源

    //數(shù)據(jù)源 let vm = {value: 0 }

    2) 然后定義一個Dep,用于存儲watcher

    //用于管理watcher的Dep對象 let Dep = function () {this.list = [];this.add = function(watcher){this.list.push(watcher)},this.notify = function(newValue){this.list.forEach(function (fn) {fn(newValue)})} };

    3) 模擬Compile出來的watchers,該demo涉及到兩個地方的重新render,一個是title,另一個是輸入框。所以寫兩個watcher,然后存入Dep

    // 模擬compile,通過對Html的解析生成一系列訂閱者(watcher) function renderInput(newValue) {let el = document.getElementById('inp');if (el) {el.value = newValue} }function renderTitle(newValue) {let el = document.getElementById('h1');if (el) {el.innerHTML = newValue} }//將解析出來的watcher存入Dep中待用 let dep = new Dep(); dep.add(renderInput); dep.add(renderTitle)

    4) 使用 Object.defineProperty 定義一個Observer

    function observer(vm, key, value) {Object.defineProperty(vm, key, {enumerable: true,configurable: true,get: function () {console.log('Get');return value},set: function (newValue) {if (value !== newValue) {value = newValueconsole.log('Update')//將變動通知給相關(guān)的訂閱者dep.notify(newValue)}}}) }

    5) 再將頁面使用的兩個方法寫出來。(Vue使用的是指令對事件進(jìn)行綁定,但是本文不涉及指令,所以用最原始的方法綁定事件)

    //頁面引用的方法 function inputChange(ev) {let value = Number.parseInt(ev.target.value);vm.value = (Number.isNaN(value)) ? 0 : value; }function btnAdd() {vm.value = vm.value + 1; }

    主要的代碼都寫好后,下面第一件事就是初始化:

    //數(shù)據(jù)初始化方法 function initMVVM(vm) {Object.keys(vm).forEach(function (key) {observer(vm, key, vm[key])}) }//初始化數(shù)據(jù)源 initMVVM(vm)//初始化頁面,將數(shù)據(jù)源渲染到UI dep.notify(vm.value);

    這樣一個簡單的基于 Object.defineProperty 的雙向數(shù)據(jù)綁定就完成了。看完的朋友有沒有對雙向數(shù)據(jù)綁定有了更多的理解了呢?如果沒有理解的話,可以將代碼復(fù)制到本地,然后循著代碼再運行下,或許能容易理解。當(dāng)然這里的代碼并不高深,只是從淺層去談?wù)摿穗p向數(shù)據(jù)綁定,所以有不足或者表達(dá)錯誤的地方,煩請各位朋友多多指正。

    這里是源碼,由于放不了動圖,所以有興趣的小伙伴可以拿下來

    最后還是補充一句,Object.defineProperty雖然好用,但并不是無懈可擊的,它對數(shù)組數(shù)據(jù)的處理并沒有想象中的好甚至表現(xiàn)很差,因此Vue團(tuán)隊專門為Vue中的數(shù)組類型編寫了額外的方法以實現(xiàn)對數(shù)組的正確監(jiān)控
    。因此,ES6中的Proxy挺身而出,拯救了ES5 中 Object.defineProperty對數(shù)組數(shù)據(jù)處理的不足。有興趣的朋友請期待筆者的下一篇博客,討論下用Proxy實現(xiàn)雙向數(shù)據(jù)綁定。

    咱們下期再見!!

    與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖

    總結(jié)

    以上是生活随笔為你收集整理的基于Object.defineProperty实现双向数据绑定的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。