<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          vue數(shù)據(jù)綁定的實現(xiàn)原理

          共 3088字,需瀏覽 7分鐘

           ·

          2021-09-27 23:55



          作者:saucxs | songEagle

          來源:原創(chuàng)

           一、vue數(shù)據(jù)綁定的實現(xiàn)原理?

          這個題目本身不是特別難,只能說是作為社招的基礎(chǔ)面試題,但是如果想回答好這道題也不是很容易。

          不信接著往下看

          1、概括回答

          vue.js是一個非常優(yōu)秀的前端開發(fā)框架,使用vue的版本是v2.x

          vue幾個核心的地方:vue實例化,虛擬DOM,模板編譯過程,數(shù)據(jù)綁定。

          我們開始回到正題,vue.js的作者尤雨溪最初就是嘗試實現(xiàn)一個類似angular1的東西,發(fā)現(xiàn)里面對于數(shù)據(jù)處理非常不優(yōu)雅,于是創(chuàng)造性的嘗試利用ES5中的Object.defineProperty來實現(xiàn)數(shù)據(jù)綁定,于是就有了最初的vue。

          vue的數(shù)據(jù)綁定的實現(xiàn)原理離不開vue中響應(yīng)式的數(shù)據(jù)處理方式。

          我們可以回想一下官網(wǎng)的圖:

          vue的響應(yīng)式基本原理:

          • 1、vue會遍歷此data中對象所有的屬性,

          • 2、并使用Object.defineProperty把這些屬性全部轉(zhuǎn)為getter/setter,

          • 3、而每個組件實例都有watcher對象,

          • 4、它會在組件渲染的過程中把屬性記錄為依賴,

          • 5、之后當依賴項的 setter被調(diào)用時,會通知watcher重新計算,從而致使它關(guān)聯(lián)的組件得以更新。

          2、亮點回答

          概括回答我們只回答了使用ES5的方法 Object.defineProperty 實現(xiàn)數(shù)據(jù)的監(jiān)聽的,那么具體是如何實現(xiàn)還是沒有講的很清楚。

          這時候我們需要問自己,如何找亮點?

          vue的響應(yīng)式原理設(shè)計三個重要對象:Observer,Watcher,Dep。

          • Observer對象:vue中的數(shù)據(jù)對象在初始化過程中轉(zhuǎn)換為Observer對象。

          • Watcher對象:將模板和Observer對象結(jié)合在一起生成Watcher實例,Watcher是訂閱者中的訂閱者。

          • Dep對象:Watcher對象和Observer對象之間紐帶,每一個Observer都有一個Dep實例,用來存儲訂閱者Watcher。

          當屬性變化會執(zhí)行主題對象Observer的dep.notify方法, 這個方法會遍歷訂閱者Watcher列表向其發(fā)送消息, Watcher會執(zhí)行run方法去更新視圖。

          依賴關(guān)系圖如下,更能方面我們的理解

          接著我們需要補充的是:模板編譯過程中的指令和數(shù)據(jù)綁定都會生成Watcher實例,實例中的watch屬性也會生成Watcher實例。

          說的這些有沒有覺得有點亂,那我們總結(jié)一下如何亮點回答

          • 1、在生命周期的initState方法中將data,prop,method,computed,watch中的數(shù)據(jù)劫持, 通過observe方法與Object.defineProperty方法將相關(guān)對象轉(zhuǎn)為換Observer對象。

          • 2、然后在initRender方法中解析模板,通過Watcher對象,Dep對象與觀察者模式將模板中的 指令與對象的數(shù)據(jù)建立依賴關(guān)系,使用全局對象Dep.target實現(xiàn)依賴收集。

          • 3、當數(shù)據(jù)變化時,setter被調(diào)用,觸發(fā)Object.defineProperty方法中的dep.notify方法, 遍歷該數(shù)據(jù)依賴列表,執(zhí)行器update方法通知Watcher進行視圖更新。

          • vue是無法檢測到對象屬性的添加和刪除,但是可以使用全局Vue.set方法(或vm.$set實例方法)。

          • vue無法檢測利用索引設(shè)置數(shù)組,但是可以使用全局Vue.set方法(或vm.$set實例方法)。

          • 無法檢測直接修改數(shù)組長度,但是可以使用splice

          然后寫一個使用Object.defineProperty實現(xiàn)監(jiān)聽變量

          1. var obj = {};

          2. var a;

          3. Object.defineProperty(obj, 'a', {

          4. get: function() {

          5. console.log('get val'); 

          6. return a;

          7. },

          8. set: function(newVal) {

          9. console.log('set val:' + newVal);

          10. a = newVal;

          11. }

          12. });

          13. obj.a; // get val

          14. obj.a = 'saucxs' //set val

          如果上面代碼格式出現(xiàn)問題,可以查看下面代碼圖片

          3、進階回答

          因為現(xiàn)在vue已經(jīng)到3了,不再是停留在2的時候,這個時候,可以把3的原理簡單說一下。

          這個時候不應(yīng)該是ES6的proxy特性上場了,proxy是ES6的新增的功能,可以用來定義對象中的操作。

          1. let p = new Proxy(target, handler);

          2. // `target` 代表需要添加代理的對象

          3. // `handler` 用來自定義對象中的操作

          如果上面代碼格式出現(xiàn)問題,可以查看下面代碼圖片

          可以很方便的使用 Proxy 來實現(xiàn)一個數(shù)據(jù)綁定和監(jiān)聽.

          1. let onWatch = (obj, setBind, getLogger) => {

          2. let handler = {

          3. get(target, property, receiver) {

          4. getLogger(target, property)

          5. return Reflect.get(target, property, receiver);

          6. },

          7. set(target, property, value, receiver) {

          8. setBind(value);

          9. return Reflect.set(target, property, value);

          10. }

          11. };

          12. return new Proxy(obj, handler);

          13. };


          14. let obj = { saucxs: 1 }

          15. let value

          16. let p = onWatch(obj, (v) => {

          17. value = v

          18. }, (target, property) => {

          19. console.log(`Get '${property}' = ${target[property]}`);

          20. })

          21. p.saucxs = songEagle // bind `value` to `songEagle`

          22. p.saucxs // -> Get 'saucxs' = songEagle

          如果上面代碼格式出現(xiàn)問題,可以查看下面代碼圖片

          然后在對比vue2和vue3的區(qū)別是什么?

          以及為啥在數(shù)據(jù)監(jiān)聽上做了升級?

          vue為什么對數(shù)組對象的深層監(jiān)聽無法實現(xiàn),因為組件每次渲染都是將data里的數(shù)據(jù)通過defineProperty進行響應(yīng)式或者雙向綁定上,之前沒有后加的屬性是不會被綁定上,也就不會觸發(fā)更新渲染。

          區(qū)別:

          1、語法層面上

          • defineProperty只能響應(yīng)首次渲染時候的屬性,

          • Proxy需要的是整體監(jiān)聽,不需要關(guān)心里面有什么屬性,而且Proxy的配置項有13種,可以做更細致的事情,這是之前的defineProperty無法達到的。

          2、兼容層面上

          • vue2.x之所以只能兼容到IE8就是因為defineProperty無法兼容IE8,其他瀏覽器也會存在輕微兼容問題。

          • proxy的話除了IE,其他瀏覽器都兼容,這次vue3還是使用了它,說明vue3直接放棄了IE的兼容考慮。


          瀏覽 54
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色A级网站 | 另类操逼暴利86 | 欧美一区二区三区四区在线 | 国产精品久久久免费 | 黄色性爱在线观看 |