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>

        為什么可以用Object.assign觸發(fā)$watch

        共 1917字,需瀏覽 4分鐘

         ·

        2022-04-01 20:27


        471fb520825b4037554820a97b5dbcb8.webp

        ????油菜花

        Object.assign,這個(gè)api在簡(jiǎn)單拷貝可枚舉對(duì)象的屬性值時(shí)經(jīng)常用到。這里介紹一個(gè)在vue2中Object.assign的用法,這個(gè)用法在官網(wǎng)文檔 有詳細(xì)介紹:

        watch:?{
        ?someObject(nvalue,?ovalue)?{
        ??...
        ?}
        }

        //?為對(duì)象添加新屬性
        this.someObject?=?Object.assign({},?this.someObject,?{?a:?1,?b:?2?})

        而且要注意的是如果像下面這樣添加上去的新屬性無(wú)法觸發(fā)更新:

        this.someObject?=?Object.assign(this.someObject,?{?a:?1,?b:?2?})

        問(wèn)題是為什么前面那種寫(xiě)法會(huì)有效?

        先看vue2文檔

        在vue2的文檔中有詳細(xì)說(shuō)明,在組件的依賴(lài)收集過(guò)程中,所有property 在被訪問(wèn)和修改時(shí)會(huì)通知變更,對(duì)于對(duì)象來(lái)說(shuō),Vue 無(wú)法檢測(cè) property 的添加或移除。

        fa240669e894a45d604b0233f3f416a3.webp

        一般情況下,在vue中,如果要對(duì)data對(duì)象中實(shí)例添加根級(jí)別property,我們可以這樣操作:

        Vue.set(someObject,?'name',?value)

        或者這樣操作

        this.$set(this.someObject,'name',2)

        但是如果我們要對(duì)一個(gè)對(duì)象添加多個(gè)屬性,同時(shí)還要保持對(duì)象的響應(yīng)性,這種情況下就要用到開(kāi)篇提到的方法。

        在mdn 上,對(duì) Object.assign 有這一句解釋?zhuān)涸摲椒ㄊ褂迷磳?duì)象的[[Get]]和目標(biāo)對(duì)象的[[Set]],所以它會(huì)調(diào)用相關(guān) getter 和 setter。對(duì)這句,我們用下面的例子a來(lái)理解。

        var?obj?=?{};
        var?c?=?null
        Object.defineProperty(obj,?'c',?{
        ??set:function(x){
        ????console.log('c被賦值:',x);
        ????c=x
        ??},
        ??get:function(){
        ????console.log('c被取出:',c)
        ????return?c
        ??}
        })

        obj.c=3??//c被賦值:3
        obj.c??//c被取出:??3

        obj?=?Object.assign(obj,?{c:?'wer23e'})?//?觸發(fā)了set!
        obj?=?Object.assign(obj,?{a:?'wer23e'})?//?由于事先未用defineProperty定義a,所以無(wú)法監(jiān)聽(tīng)
        //?由于目標(biāo)對(duì)象未定義屬性,無(wú)法監(jiān)聽(tīng)
        obj?=?Object.assign({},obj,?{a:?'wer23e',c:?'dfrr23e'})?

        通過(guò)這段代碼可以理解上面說(shuō)的“Object.assign會(huì)使用目標(biāo)對(duì)象的[[Set]]”,同時(shí),這段代碼也演示了vue2中響應(yīng)原理,因?yàn)関ue2中所有需要響應(yīng)的屬性都是用 Object.defineProperty 進(jìn)行響應(yīng)綁定,這樣所有的訪問(wèn)和修改動(dòng)作都會(huì)被追蹤到。但是對(duì)于沒(méi)有事先被 Object.defineProperty定義的屬性,比如添加一個(gè)屬性就無(wú)法監(jiān)聽(tīng)到了。在上面的示例中,即使我用文檔提到的用法 obj = Object.assign({},obj, {a: 'wer23e',c: 'dfrr23e'}) 仍然無(wú)法觸發(fā)c屬性的 set。走到這一步,是不是得看watch源碼了?其實(shí)不必!

        用Object.assign觸發(fā)watch原理

        針對(duì)這個(gè)問(wèn)題,watch的源碼不必看,但是 Object.assign 的源碼必須要看,

        if?(typeof?Object.assign?!==?'function')?{
        ??//?Must?be?writable:?true,?enumerable:?false,?configurable:?true
        ??Object.defineProperty(Object,?"assign",?{
        ????value:?function?assign(target,?varArgs)?{?//?.length?of?function?is?2
        ??????'use?strict';
        ??????if?(target?===?null?||?target?===?undefined)?{
        ????????throw?new?TypeError('Cannot?convert?undefined?or?null?to?object');
        ??????}

        ??????var?to?=?Object(target);

        ??????for?(var?index?=?1;?index?arguments.length;?index++)?{
        ????????var?nextSource?=?arguments[index];

        ????????if?(nextSource?!==?null?&&?nextSource?!==?undefined)?{
        ??????????for?(var?nextKey?in?nextSource)?{
        ????????????//?Avoid?bugs?when?hasOwnProperty?is?shadowed
        ????????????if?(Object.prototype.hasOwnProperty.call(nextSource,?nextKey))?{
        ??????????????to[nextKey]?=?nextSource[nextKey];
        ????????????}
        ??????????}
        ????????}
        ??????}
        ??????return?to;
        ????},
        ????writable:?true,
        ????configurable:?true
        ??});
        }

        其實(shí)就是把 assign 方法中的參數(shù)的可枚舉屬性全部復(fù)制到此方法的第一參數(shù)上去?;仡^再去理解下例子a, obj = Object.assign({},obj, {a: 'wer23e',c: 'dfrr23e'}) 無(wú)法觸發(fā)c屬性的 set 函數(shù)是因?yàn)?,obj引用關(guān)系已經(jīng)被改變了,不再是原來(lái)那個(gè)對(duì)象,也就沒(méi)有了對(duì)應(yīng)的屬性監(jiān)控,但是為什么官方文檔會(huì)建議這么用呢?

        接下來(lái),我寫(xiě)了個(gè)小demo,來(lái)幫你理解,你可以試下效果