實(shí)現(xiàn)一個(gè)簡單得數(shù)據(jù)響應(yīng)系統(tǒng)
1、Dep
其實(shí),這就是一個(gè)依賴收集的容器, depend
收集依賴, notify
觸發(fā)依賴
class Dep{ constructor() { this._subs = []; } depend () { this._subs.push(Dep.target) } notify() { this._subs.forEach(item => { item.fn(); }) } } // 其實(shí)就是 dep 和 watcher 基情滿滿的開始,watcher 中用到 // 通過一個(gè)全局屬性來存 watcher Dep.target = null; function pushTarget(watch) { Dep.target = watch; } function popTarget() { Dep.target = null; }
2、了解 obverser
遞歸,將 data 對(duì)象所有屬性轉(zhuǎn)化為訪問器屬性
// 轉(zhuǎn)為訪問器屬性 function defineReactive (obj, key, val, shallow) { // 創(chuàng)建一個(gè)依賴收集容器 let dep = new Dep(); let childOb = !shallow && observe(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { if(Dep.target) { // 收集依賴 dep.depend(); } return val; // ... }, set: function reactiveSetter (newVal) { if(newVal === val) return; // 繼續(xù)遞歸遍歷 observe(newVal); // 觸發(fā)依賴 dep.notify(); // ... } }) } class Observer{ constructor(data) { this.walk(data); } walk(data) { const keys = Object.keys(data) for (let i = 0; i < keys.length; i++) { defineReactive(data, keys[i], data[keys[i]]) } } } // 遞歸,將 data 對(duì)象所有屬性轉(zhuǎn)化為訪問器屬性 function observe (data) { if(Object.prototype.toString.call(data) !== '[object Object]') return; new Observer(data); }
此時(shí)就可以把任意一個(gè)對(duì)象的全部屬性轉(zhuǎn)為訪問器
3、了解 watch 和 observer
const data = { a: 1, b: 2 } // 首先監(jiān)控一個(gè)對(duì)象 observe(data);
watcher
的主要功能是檢測某個(gè)屬性,當(dāng)屬性變化時(shí)觸發(fā)一個(gè)回調(diào)
class Watcher{ /** * @params {Function} exp 一個(gè)屬性表達(dá)式 * @params {Function} fn 回調(diào) */ constructor(exp, fn) { this.exp = exp; this.fn = fn; // 存 watcher // Dep.target = this; pushTarget(this); // 先執(zhí)行一次表達(dá)式函數(shù),會(huì)在調(diào)用過程中, // 觸發(fā)到 data.a 的訪問器, data.a 的 get 被執(zhí)行, // 觸發(fā) dep.depend() 開始收集依賴 this.exp(); // 釋放 Dep.target popTarget(); } } // new Watcher 這樣一個(gè)依賴就被收集了 new Watcher(() => { return data.a + data.b; }, () => { console.log('change') })
4、觸發(fā)依賴
data.a = 3; // change data.b = 3; // change
5、總結(jié)一下流程
- 把一個(gè)對(duì)象的全部屬性轉(zhuǎn)化為訪問器
- 當(dāng)為某一個(gè)屬性增加
watcher
時(shí),會(huì)觸發(fā)改屬性的get
,get
函數(shù)中會(huì)把該watcher
存到該屬性的dep
依賴容器中 - 當(dāng)這個(gè)屬性發(fā)生變化時(shí),會(huì)出發(fā)改屬性的
set
的方法,set
函數(shù)中會(huì)把dep
存的依賴都執(zhí)行
到此這篇關(guān)于實(shí)現(xiàn)一個(gè)簡單得數(shù)據(jù)響應(yīng)系統(tǒng)的文章就介紹到這了,更多相關(guān)數(shù)據(jù)響應(yīng)系統(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript前端迭代器Iterator與生成器Generator講解
這篇文章主要為大家介紹了JavaScript前端迭代器Iterator與生成器Generator講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08JavaScript架構(gòu)搭建前端監(jiān)控如何采集異常數(shù)據(jù)
這篇文章主要為大家介紹了JavaScript架構(gòu)搭建前端監(jiān)控如何采集異常數(shù)據(jù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06js實(shí)現(xiàn)兔年轉(zhuǎn)圈圈動(dòng)畫示例
這篇文章主要為大家介紹了js實(shí)現(xiàn)兔年轉(zhuǎn)圈圈動(dòng)畫示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01微信小程序 網(wǎng)絡(luò)API發(fā)起請(qǐng)求詳解
這篇文章主要介紹了微信小程序 網(wǎng)絡(luò)API發(fā)起請(qǐng)求詳解的相關(guān)資料,需要的朋友可以參考下2016-11-11JS實(shí)現(xiàn)大數(shù)相加大數(shù)相乘示例詳解
這篇文章主要為大家介紹了JS實(shí)現(xiàn)大數(shù)相加大數(shù)相乘示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08自定義range?sliders滑塊實(shí)現(xiàn)元素拖動(dòng)方法
這篇文章主要為大家介紹了自定義range?sliders滑塊實(shí)現(xiàn)元素拖動(dòng)方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08JavaScript 運(yùn)行機(jī)制詳解再淺談Event Loop
這篇文章主要介紹了JavaScript 運(yùn)行機(jī)制詳解及淺談了Event Loop,感興趣的小伙伴可以和小編一起閱讀下面文章的具體內(nèi)容2021-09-09