摘要:源碼自問自答響應(yīng)式原理最近看了源碼和源碼分析類的文章感覺明白了很多,但是仔細(xì)想想?yún)s說不出個(gè)所以然。會(huì)在對(duì)象的這個(gè)被獲取時(shí)觸發(fā),會(huì)在這個(gè)對(duì)象的被修改時(shí)觸發(fā)。在初始化時(shí),將對(duì)象上的所有,都包裝成擁有和的屬性。
vue 源碼自問自答-響應(yīng)式原理
最近看了 Vue 源碼和源碼分析類的文章,感覺明白了很多,但是仔細(xì)想想?yún)s說不出個(gè)所以然。
所以打算把自己掌握的知識(shí),試著組織成自己的語言表達(dá)出來
不打算平鋪直敘的寫清楚 vue 源碼的前因后果和全部細(xì)節(jié),而是以自問自答的形式,回答我自己之前的疑惑,
如果有錯(cuò)誤的地方,歡迎指正哈~
Vue 的雙向數(shù)據(jù)綁定原理Vue 實(shí)現(xiàn)響應(yīng)式的核心 API 是 ES5 的 Object.defineProperty(obj,key,descriptor),Vue 的「響應(yīng)式」和「依賴收集」都依靠這個(gè) API
它接受 3 個(gè)參數(shù),分別是 obj / key / 描述符,返回的是一個(gè)包裝后的對(duì)象
它的作用就是,用這個(gè) API 包裝過后的對(duì)象可以擁有 getter 和 setter 函數(shù)。
getter 會(huì)在對(duì)象的這個(gè) key 被獲取時(shí)觸發(fā),setter 會(huì)在這個(gè)對(duì)象的 key 被修改時(shí)觸發(fā)。
一個(gè) Vue 項(xiàng)目的開始, 通常是從 Vue 構(gòu)造函數(shù)的實(shí)例化開始的。
new Vue()的時(shí)候會(huì)執(zhí)行一個(gè)_init()方法,會(huì)初始化屬性,比如 props/event/生命周期鉤子,也包括 data 對(duì)象的初始化。
Vue 在初始化時(shí),將 data 對(duì)象上的所有 key,都包裝成擁有 getter 和 setter 的屬性。
渲染頁面時(shí),會(huì)執(zhí)行 render function(無論是用 template 還是 render 最終都會(huì)生成 render 函數(shù))
執(zhí)行 render function 會(huì)獲取 data 對(duì)象上的屬性,所以會(huì)觸發(fā)對(duì)應(yīng)屬性的 getter 函數(shù)
getter 觸發(fā)時(shí),主要就做 2 個(gè)事情。 1.把值返回 2.依賴收集,也就是講 watcher 存放到 Dep 實(shí)例的一個(gè)隊(duì)列里。
當(dāng)修改對(duì)象的值觸發(fā) setter,setter 同樣是做 2 個(gè)事情。1.把 newVal 設(shè)置好 2.用一個(gè)循環(huán)通知之前存放在 dep 實(shí)例中 watcher 對(duì)象們,watcher 對(duì)象調(diào)用各自的 update 方法來更新視圖
實(shí)現(xiàn)雙向數(shù)據(jù)綁定的demo1 - 忽略「收集依賴」的版本function cb() { console.log("更新視圖"); } function defineReactve(obj, key, val) { Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: () => { console.log("觸發(fā)了getter"); return val; }, set: newVal => { console.log("觸發(fā)了setter"); if (newVal === val) return; val = newVal; cb() } }); } function observe(data) { function walk(data) { Object.keys(data).forEach(key => { if (typeof data[key] === "object") { walk(data[key]); } else { defineReactve(data, key, data[key]); } }); } walk(data); } class Vue { constructor(options) { this._data = options.data; observe(this._data); } } var vm = new Vue({ data: { msg: "test", person: { name: "ziwei", age: 18 } } }); vm._data.person.name = "hello" // 觸發(fā)setter和cb函數(shù),從而視圖更新實(shí)現(xiàn)雙向數(shù)據(jù)綁定的demo2 - 「收集依賴」的版本
function defineReactve( obj, key, val ) { const dep = new Dep() Object.defineProperty( obj, key, { enumerable: true, configurable: true, get: () => { console.log( "觸發(fā)了getter" ); dep.addSub(Dep.target) return val; }, set: newVal => { console.log( "觸發(fā)了setter" ); if ( newVal === val ) return; val = newVal; dep.notify() // 通知隊(duì)列的wather去update視圖 } } ); } function observe( data ) { function walk( data ) { Object.keys( data ).forEach( key => { if ( typeof data[ key ] === "object" ) { walk( data[ key ] ); } else { defineReactve( data, key, data[ key ] ); } } ); } walk( data ); } class Dep{ constructor(){ this.subs = [] } addSub(){ this.subs.push(Dep.target) } notify(){ this.subs.forEach(sub => { sub.update() }) } } Dep.target = null class Watcher{ constructor(){ Dep.target = this } update(){ console.log("update更新視圖啦~") } } class Vue { constructor( options ) { this._data = options.data; observe( this._data ); new Watcher() // 模擬頁面渲染,觸發(fā)getter,依賴收集的效果 this._data.person.name } } var vm = new Vue( { data: { msg: "test", person: { name: "ziwei", age: 18 } } } ); vm._data.person.name = "hello"一些省略掉的環(huán)節(jié)
這樣就是 Vue 響應(yīng)式的一個(gè)基本原理,不過我描述的過程中,也省略了很多環(huán)節(jié),比如
Vue 是如何實(shí)現(xiàn)給 data 對(duì)象上的屬性都擁有 getter 和 setter 的
為什么要進(jìn)行「依賴收集」,
如何避免重復(fù)「收集依賴」
watcher 調(diào)用 update,也并不是直接更新視圖。實(shí)現(xiàn)上中間還有 patch 的過程以及使用隊(duì)列來異步更新的策略。
Vue 是如何實(shí)現(xiàn)給 data 對(duì)象上的屬性都擁有 getter 和 setter 的
通過循環(huán)data對(duì)象,給對(duì)象的每一個(gè)key,用Object.defineProperty包裝 遍歷時(shí),如果發(fā)現(xiàn)data[key]也是對(duì)象的話,需要用遞歸
為什么要進(jìn)行「依賴收集」?
舉2個(gè)場(chǎng)景的栗子
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98913.html
摘要:請(qǐng)注意,我們?cè)诹牧膯卧獪y(cè)試遇到問題多思考多查閱多驗(yàn)證,方能有所得,再勤快點(diǎn)樂于分享,才能寫出好文章。單元測(cè)試是指對(duì)軟件中的最小可測(cè)試單元進(jìn)行檢查和驗(yàn)證。 JAVA容器-自問自答學(xué)HashMap 這次我和大家一起學(xué)習(xí)HashMap,HashMap我們?cè)诠ぷ髦薪?jīng)常會(huì)使用,而且面試中也很頻繁會(huì)問到,因?yàn)樗锩嫣N(yùn)含著很多知識(shí)點(diǎn),可以很好的考察個(gè)人基礎(chǔ)。但一個(gè)這么重要的東西,我為什么沒有在一開始...
摘要:用偽代碼來模擬下長(zhǎng)輪詢的過程前端利用下面函數(shù)進(jìn)行請(qǐng)求后端代碼做如下更改利用隨機(jī)數(shù)的大小來模擬是否有新數(shù)據(jù)有新數(shù)據(jù)來了長(zhǎng)輪詢的確減少了請(qǐng)求的次數(shù),但是它也有著很大的問題,那就是耗費(fèi)服務(wù)器的資源。 寫在前面 最近由于利用node重構(gòu)某個(gè)項(xiàng)目,項(xiàng)目中有一個(gè)實(shí)時(shí)聊天的功能,于是就研究了一下聊天室,在線demo|源碼,歡迎大家反饋。這個(gè)聊天室的主要利用到了socket.io和express。這個(gè)...
閱讀 1981·2019-08-30 15:54
閱讀 3608·2019-08-29 13:07
閱讀 3133·2019-08-29 12:39
閱讀 1799·2019-08-26 12:13
閱讀 1555·2019-08-23 18:31
閱讀 2167·2019-08-23 18:05
閱讀 1856·2019-08-23 18:00
閱讀 1052·2019-08-23 17:15