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