前端面試題八@楊志剛

vue中雙向數(shù)據(jù)綁定是如何實現(xiàn)的


????數(shù)據(jù)雙向綁定,一個是監(jiān)聽頁面的數(shù)據(jù)變化晌端,一個是將數(shù)據(jù)變化映射到頁面捅暴。

分成兩個進程,一個進程是對掛載目標元素模板里的v-model和{{ }}這兩個指令進行編譯(綠色)咧纠。另一個進程是對傳進去的data對象里面的數(shù)據(jù)進行監(jiān)聽(紅色)蓬痒。

紅色:

當你把一個普通的 JavaScript 對象傳給 Vue 實例的data選項,Vue 將遍歷此對象所有的屬性漆羔,并使用Object.defineProperty把這些屬性全部加上set和get訪問器梧奢,這樣在設置data的屬性值的時候,會觸發(fā)set方法演痒,那么set方法主要有兩個作用亲轨,一是改變data里面的屬性值,二是發(fā)出數(shù)據(jù)變化的通知鸟顺。Observer作為數(shù)據(jù)的觀察者惦蚊,讓數(shù)據(jù)對象的讀寫操作都處于自己的監(jiān)管之下,Dep作為Watcher(訂閱器)的收集者讯嫂,當數(shù)據(jù)發(fā)生變化set會發(fā)出通知蹦锋,會被Observer觀察到,然后由Dep通知到Watcher欧芽,最后更新視圖莉掂。

綠色:

指令解析器Compile,對每個節(jié)點元素進行掃描和解析千扔,將相關(guān)指令對應初始化成一個訂閱者Watcher憎妙,同樣由Dep進行收集,然后由Dep通知到Watcher昏鹃,最后更新視圖尚氛。

節(jié)點介紹

數(shù)據(jù)監(jiān)聽器觀察者Observer,能夠?qū)?shù)據(jù)對象的所有屬性進行監(jiān)聽洞渤,讓數(shù)據(jù)對象的讀寫操作都處于自己的監(jiān)管之下阅嘶,當數(shù)據(jù)發(fā)生變化set會發(fā)出通知,會被Observer觀察到载迄,然后由Dep通知到Watcher讯柔,最后更新視圖。

實現(xiàn)數(shù)據(jù)的雙向綁定护昧,首先要對數(shù)據(jù)進行劫持監(jiān)聽魂迄,所以我們需要設置一個監(jiān)聽器Observer,用來監(jiān)聽所有屬性

Watcher將數(shù)據(jù)監(jiān)聽器和指令解析器連接起來惋耙,數(shù)據(jù)的屬性變動時网棍,執(zhí)行指令綁定的相應回調(diào)函數(shù),

1.如果屬性發(fā)上變化了望抽,就需要告訴訂閱者Watcher看是否需要更新冶匹。

指令解析器Compile陷虎,

對每個節(jié)點元素進行掃描和解析,將相關(guān)指令對應初始化成一個訂閱者Watcher

Dep:因為訂閱者是有很多個,所以我們需要有一個消息訂閱器Dep來專門收集這些訂閱者,然后在監(jiān)聽器Observer和訂閱者Watcher之間進行統(tǒng)一管理的

詳述虛擬DOM中的diff算法

Vue的核心是雙向綁定和虛擬DOM(下文我們簡稱為vdom)昂利,vdom是樹狀結(jié)構(gòu),其節(jié)點為vnode铁坎,vnode和瀏覽器DOM中的Node一一對應蜂奸,通過vnode的elm屬性可以訪問到對應的Node。

vdom因為是純粹的JS對象硬萍,所以操作它會很高效扩所,但是vdom的變更最終會轉(zhuǎn)換成DOM操作,為了實現(xiàn)高效的DOM操作襟铭,一套高效的虛擬DOM diff算法顯得很有必要碌奉。

vdom: 雙向綁定虛擬dom短曾。下面是vue的diff算法參考圖

need-to-insert-img

一寒砖、簡單的diff設計:

遍歷newVdom的節(jié)點,找到他在oldVdom中的位置嫉拐,找到就移動對應的dom元素哩都,沒找到說明是新增節(jié)點,則創(chuàng)建一個節(jié)點插入婉徘。遍歷完后如果oldVdom中還有沒有處理過的節(jié)點漠嵌,說明這些節(jié)點在newVdom中被刪除了,刪除它們即可盖呼。

二儒鹿、Vue的diff實現(xiàn):

1、優(yōu)先處理特殊場景

(1)几晤、頭部的同類型節(jié)點约炎、尾部的同類型節(jié)點

這類節(jié)點更新前后位置沒有發(fā)生變化,所以不用移動它們對應的DOM

(2)蟹瘾、頭尾/尾頭的同類型節(jié)點

這類節(jié)點位置很明確圾浅,不需要再花心思查找,直接移動DOM就好

處理了這些場景之后憾朴,一方面一些不需要做移動的DOM得到快速處理狸捕,另一方面待處理節(jié)點變少,縮小了后續(xù)操作的處理范圍众雷,性能也得到提升

2灸拍、“原地復用”

“原地復用”是指Vue會盡可能復用DOM做祝,盡可能不發(fā)生DOM的移動。Vue在判斷更新前后指針是否指向同一個節(jié)點鸡岗,其實不要求它們真實引用同一個DOM節(jié)點剖淀,實際上它僅判斷指向的是否是同類節(jié)點

虛擬DOM對比時,會用到diff算法

虛擬DOM什么時候會被比對纤房?

當數(shù)據(jù)發(fā)生變化的時候就會被比對

那什么時候數(shù)據(jù)會發(fā)生改變呢纵隔?

要么改變了state,要么改變了props(props的改變其實是他的父組件的state發(fā)生了改變)

setState方法炮姨,其實是異步的捌刮,為什么是異步的?實際為了提升React底層的性能舒岸,假設:調(diào)用三次setState變更三組數(shù)據(jù)绅作,大家想頁面會怎么做或者說React會怎么做?我們想的是React可能會做三次比對更新三次視圖蛾派。又假設三次更新間隔非常小俄认,這樣會耗費性能,React可以把三次合并為一次洪乍,只去做一次虛擬DOM的比對眯杏,然后更新一次視圖,這樣的話就可以省去兩次比對性能上的耗費壳澳。

同層比對岂贩,如果一致,那么繼續(xù)比對第二層巷波,如果比對一樣了萎津,繼續(xù)往下比對。

如果比對到不一樣了抹镊,React會這么做锉屈,它不會再繼續(xù)往下比對了,而是從不一樣的這一層開始直接用新的覆蓋掉就得DOM節(jié)點,這樣的話豈不是性能并未得到最大提升垮耳?這樣的話會造成重復節(jié)點的浪費颈渊,。那這樣比對會有什么好處呢氨菇?同層比對帶來的好處就是比對的算法特別簡單儡炼,雖然可能會造成DOM上的重新渲染的浪費,但是大大的減少了虛擬DOM之間比對的算法上的性能消耗查蓉,所以React中采用了同層比對的算法乌询。

遍歷時候key的問題:

假如:數(shù)組中有五條數(shù)據(jù),渲染到頁面豌研,然后生成五個虛擬DOM樹妹田,接下來我往里面增加了一條數(shù)據(jù)于是數(shù)據(jù)發(fā)生變化會生成一個新的虛擬DOM樹唬党,然后我們會做兩個虛擬DOM的比對也就是上下進行比對匹配關(guān)系,如果每一個虛擬DOM的節(jié)點沒有一個key值鬼佣,它就沒有一個自己的名字驶拱,當我們在做兩個虛擬DOM樹的比對的時候節(jié)點和節(jié)點之間的關(guān)系就很難被確立,我們得做兩層循環(huán)的比較晶衷,這樣的話比較起來就很麻煩了蓝纲,當然也是很耗費性能的。

我們可以這樣優(yōu)化晌纫,假如我們在做DOM節(jié)點的循環(huán)的時候税迷,我們可以給每個節(jié)點起個名字,A锹漱、B箭养、C、D哥牍、E在第二次循環(huán)的時候我們有六個毕泌,以前的ABCDE還存在還是叫做ABCDE,我又增加了一個節(jié)點Z進來這個時候比對就很簡單了嗅辣,我們根據(jù)他們的名字進行比對撼泛,馬上就能知道ABCDE都一致,可以繼續(xù)復用辩诞,只有Z不同坎弯,我們快速的建立關(guān)聯(lián)后把Z增加到這個DOM樹上就可以了。所以極大的提升了虛擬DOM比對的性能译暂。

如果提升性能有個前提我們盡量不要用下標,因為大家看按照下標的話右圖ABCDE撩炊,下面新的DOM樹ABCDE和上面的其實不再是對應的關(guān)系了外永,對導致key值不穩(wěn)定,key值是變化的拧咳,失去了存在的意義了伯顶。那用什么比較合適呢?唯一不變化的骆膝、穩(wěn)定的值祭衩。

大神總結(jié)

Vue的雙向數(shù)據(jù)綁定是通過數(shù)據(jù)劫持結(jié)合發(fā)布者訂閱者模式來實現(xiàn)的

個人理解:在new Vue的時候,在Observer中通過Object.defineProperty()達到數(shù)據(jù)劫持阅签,代理所有數(shù)據(jù)的getter和setter屬性掐暮,在每次觸發(fā)setter的時候,都會通過Dep來通知Watcher政钟,Watcher作為Observer數(shù)據(jù)監(jiān)聽器與Compile模板解析器之間的橋梁路克,當Observer監(jiān)聽到數(shù)據(jù)發(fā)生改變的時候樟结,通過Updater來通知Compile更新視圖

而Compile通過Watcher訂閱對應數(shù)據(jù),綁定更新函數(shù)精算,通過Dep來添加訂閱者瓢宦,達到雙向綁定

vue提供了幾種腳手架模板

vue-cli + vue2.0 + vuex + vue-router + axios + element-ui(不知道這道題指什么,所以寫了vue全家桶)

mvvm開發(fā)模式討論

1.標準MVVM(由View實例化Model)

need-to-insert-img

這種由View調(diào)用Model, 并具體由View負責Model實例化的方式是最為普遍的灰羽,非常適合于需要跨平臺的應用驮履。當然,Model并不知道View的存在廉嚼,因此View要承擔所有的界面邏輯疲吸,好在WPF已經(jīng)給出了足夠多的解決方案,觸發(fā)器前鹅,模板摘悴。基本絕大多數(shù)需求都能滿足舰绘。

2.插件結(jié)構(gòu)(Model實例化View)

這種做法的最常見場合應該是插件系統(tǒng)蹂喻。一個個的Model其實是一個個的插件,它們應該具備自治性捂寿。因此口四,應該由自身負責界面的產(chǎn)生。

?? 它的好處是可以通過Model更加精細的調(diào)節(jié)View的行為秦陋,你可以在任何時候獲得View內(nèi)部ListBox的SelectIndex, 而不用麻煩的用Binding蔓彩。 打個比方說,游戲開發(fā)中驳概,你需要隨時控制物體的運動速度和方向赤嚼,這樣Model就必須控制View. 綁定很難解決這類問題。

need-to-insert-img

?每一個功能庫都有完整的自治性顺又,當你將該功能庫拷貝到主框架之下時更卒,它就會自動加載,由Model負責View的生成稚照。一切合情合理蹂空。

3. 組裝車間(第三方組裝View和Model)

這種思路來自于工廠方法,類似于裝配車間果录,View和Model都不負責互相的實例化上枕。而有一個“管理器”負責組裝它們。這樣的好處在于可配置弱恒。你可以通過配置文件動態(tài)的改變View.

這種做法徹底的隔絕了View和Model, 同時通過配置選項辨萍,可以隨時修改View〗锉耍可謂是一種不錯的設計分瘦。 但是蘸泻,必需看到,對于View來說,Model沒有任何管理的權(quán)限嘲玫。下圖展示了它的基本邏輯:

need-to-insert-img

如果最終你依舊需要兩邊互相控制悦施,可以考慮采用dynamic關(guān)鍵字。

名稱組裝邏輯適用場合缺點備注

標準MVVMView實例化Model常用的跨平臺場合Model無法控制任何View適用于自底向上的分層設計

Model實例化ViewModel實例化View插件結(jié)構(gòu)或用于游戲開發(fā)存在一定的耦合適用于按功能劃分的插件型類庫設計去团,或要求Model大量控制View的場合

組裝車間第三方管理器實例化和組裝Model和View可動態(tài)替換所有View兩者徹底隔絕抡诞,沒有控制靈活性大型系統(tǒng)的嚴格設計

常見的幾種mvvm的實現(xiàn)方式

1.發(fā)布者-訂閱模式(backbone.js)

2.臟值檢查(angular.js)

3.數(shù)據(jù)劫持(vue.js)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市土陪,隨后出現(xiàn)的幾起案子昼汗,更是在濱河造成了極大的恐慌,老刑警劉巖鬼雀,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顷窒,死亡現(xiàn)場離奇詭異,居然都是意外死亡源哩,警方通過查閱死者的電腦和手機鞋吉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來励烦,“玉大人谓着,你說我怎么就攤上這事√陈樱” “怎么了赊锚?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長屉栓。 經(jīng)常有香客問我舷蒲,道長,這世上最難降的妖魔是什么系瓢? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任阿纤,我火速辦了婚禮,結(jié)果婚禮上夷陋,老公的妹妹穿的比我還像新娘。我一直安慰自己胰锌,他們只是感情好骗绕,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著资昧,像睡著了一般酬土。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上格带,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天撤缴,我揣著相機與錄音刹枉,去河邊找鬼。 笑死屈呕,一個胖子當著我的面吹牛微宝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播虎眨,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼蟋软,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嗽桩?” 一聲冷哼從身側(cè)響起岳守,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎碌冶,沒想到半個月后湿痢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡扑庞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年譬重,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嫩挤。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡害幅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出岂昭,到底是詐尸還是另有隱情以现,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布约啊,位于F島的核電站邑遏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏恰矩。R本人自食惡果不足惜记盒,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望外傅。 院中可真熱鬧纪吮,春花似錦、人聲如沸萎胰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽技竟。三九已至冰肴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背熙尉。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工联逻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人检痰。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓包归,卻偏偏與公主長得像,于是被迫代替她去往敵國和親攀细。 傳聞我的和親對象是個殘疾皇子箫踩,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容