1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 3088字,需瀏覽 7分鐘

         ·

        2021-09-27 23:55



        作者:saucxs | songEagle

        來源:原創(chuàng)

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

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

        不信接著往下看

        1、概括回答

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

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

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

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

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

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

        • 1、vue會(huì)遍歷此data中對(duì)象所有的屬性,

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

        • 3、而每個(gè)組件實(shí)例都有watcher對(duì)象,

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

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

        2、亮點(diǎn)回答

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

        這時(shí)候我們需要問自己,如何找亮點(diǎn)?

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

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

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

        • Dep對(duì)象:Watcher對(duì)象和Observer對(duì)象之間紐帶,每一個(gè)Observer都有一個(gè)Dep實(shí)例,用來存儲(chǔ)訂閱者Watcher。

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

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

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

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

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

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

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

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

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

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

        然后寫一個(gè)使用Object.defineProperty實(shí)現(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、進(jìn)階回答

        因?yàn)楝F(xiàn)在vue已經(jīng)到3了,不再是停留在2的時(shí)候,這個(gè)時(shí)候,可以把3的原理簡單說一下。

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

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

        2. // `target` 代表需要添加代理的對(duì)象

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

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

        可以很方便的使用 Proxy 來實(shí)現(xiàn)一個(gè)數(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)問題,可以查看下面代碼圖片

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

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

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

        區(qū)別:

        1、語法層面上

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

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

        2、兼容層面上

        • vue2.x之所以只能兼容到IE8就是因?yàn)閐efineProperty無法兼容IE8,其他瀏覽器也會(huì)存在輕微兼容問題。

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


        瀏覽 54
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            91人妻人人澡人人精品 | 99re视频这里只有精品 | 无码视频在线观看 | 91嫩草国产露脸精品国产 | 我解开岳乳罩吃她胸 | 日韩一区二区三区无码免费播放 | 久久四区 | 久久丫丫 | 色小说香蕉 | 大鸡巴插入 |