How to dynamically add responsive properties to vm instances in vuejs?

the relevant chapter on vue.js "s official website is explained as follows:
the link is ide/list.html-sharpkey" rel=" nofollow noreferrer "> https://cn.vuejs.org/v2/guide.

.

sometimes you may need to assign multiple new properties to existing objects, such as using Object.assign () or
_ .extend (). In this case, you should create a new object with the properties of both objects. So, if you want to add new responsive attributes, don"t go like this:

Object.assign(vm.userProfile, {
  age: 27,
  favoriteColor: "Vue Green"
})

you should do this:

vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: "Vue Green"
})

I tested it with code, and it"s true, but I don"t understand why. It"s strange. Let"s give an explanation.

Jul.29,2021

the result of userProfile is the same as that of

.
is the same page on the official website, as mentioned earlier-for instances that have been created, Vue cannot dynamically add root-level responsive attributes

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 

vm.b = 2
// `vm.b` 
The first way to write the

question is equivalent to vm.b = 2 . For the created instance userProfile , for adding attributes to userProfile , Vue cannot be dynamically detected. The second way of writing
is equivalent to vm.a = XX . First, assign the properties of two objects to an empty object, and then assign the object to userprofile , which is directly re-assigned to the root-level object, which is different from the nature of adding and deleting object attributes. That's what I think.


I agree to go up to the next floor. In fact, I have already explained it enough. Let me add some relevant knowledge of Object.assign

.
if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }

from the polyfill implementation of Object, we can see that attribute replication is realized by assignment (the disadvantage of this is that only root attributes are deep copies and others are shallow copies)
is actually no different from vm.b = 2 . Attributes are added to the instances that have been created, and Vue does not implement the getter/setter conversion process for these attributes. Therefore, it is impossible to bind the data of these attributes in both directions, and why the assignment of vm.userProfile can trigger this mechanism is not known without looking at the source code.
attach an official note:

Vue does not allow new root-level responsive attributes (root-level reactive property)) to be dynamically added to instances that have been created. However, it can use the Vue.set (object, key, value) method to add response properties to nested objects.
sometimes you want to add properties to an existing object, such as using the Object.assign () or _ .extend () method to add attributes. However, new properties added to the object do not trigger updates. In this case, you can create a new object that contains the properties of the original object and the new properties.

you asked such a good question that I didn't notice this detail before. No, no, no. In order to answer your question, I start from the principle of Vue to explain may better find this reason:
PS: can follow my article Vue principle analysis, write their own vue it is easier to understand .

We all know that the response principle of Vue uses the attribute Object.defineProperty . We can imitate Vue to write a way to define response:

function defineReactive (obj, key, value){
  Object.defineProperty(obj,key,{
    get:function(){
      console.log("get"+JSON.stringify(value));
      return value;//
    },
    set:function(newValue){
      if(newValue === value){
        return;//
      }
      value = newValue;//
      console.log("set"+JSON.stringify(value));
    }
  })
}

the above method, we can see that its principle is to declare the response by Object.defineProperty declares the data instance of Vue, in which we can intercept the get and set methods.
so, at this point we declare an object obj :

let obj = {
    userProfile: {
        name: ''
    }
}

you can think of this obj as the data attribute in vue .
then, we declare the response:

Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key]);
})

if the first method is adopted:

Object.assign(obj.userProfile, {
  age: 'age'
})
obj.userProfile.age = '';

We can find that the output looks like this:

getset
:


:

set
:Object.defineProperty

F12


:


vueObject.defineProperty()svuevuevuevueapi Vue.$setVue.$deleteVue.prototype Object.assign({}, vm.userProfile,{...}) vue Object.assign() , MDN.aspx)


fork @
https://codepen.io/rushui/ful...
https://codepen.io/rushui/ful...
debuggervue.js


https://codepen.io/rushui/ful...

clipboard.png

vue

vm.userProfilegetter

clipboard.png

sourceKey_data, keyuserProfile, sharedPropertyDefinitionvue
gettervm["_data"]["userProfile"]name,vuegettersetter

vm.userProfilegetter

userProfilegetter

clipboard.png

Object.assignvm.userProfile

vm.userProfilesetter

Object.assignvm.userProfilesetter

clipboard.png

newValvalvue(NaN??)
settersetter1017valvue

1019observe(newVal)

observeobserver instance.

clipboard.png

observer

clipboard.png

this.walk

clipboard.png

1

vue

https://codepen.io/rushui/ful...

setter

vue1004userProfilesetter setter,

clipboard.png

MDNObject.assign,?
Object.assign(target, ...sources)

Object.assign [[Get]][[Set]] getter setter


clipboard.png

28userProfilenamegettersetteragevueagegettersetter, ageuserProfileuserProfilesetter

setter

28userProfilesetter

https://codepen.io/rushui/ful...

setter

clipboard.png

but does not escape the judgment defined by the author, that is, if the two values are equal, they will be returned directly. But why are these two values equal?

Why are val and newVal equal this time

Why are val and newVal exactly the same? the original Object.assign method merges attributes onto the userProfile object, while userProfile is actually a pointer to an object in memory, and there is only one object, so when you merge, the reference to this object does not change, the object in memory adds the property age, and the value stored by userProfile itself is the address, and this address does not change. So the acquisition before and after is the same object. This object has been updated to the latest by Object.assign in the current situation.
raises the question: why don't vue authors compare snapshots of val, but references? Look confused.

< H2 > summarize < / H2 >

so now that I have finished debugging, neither of the latter two methods is feasible and will be terminated without going into the setter and getter of the vue processing properties.

Menu