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:
get
set
:
:
set
:Object.defineProperty
F12
:
vueObject.defineProperty()svuevuevuevueapi Vue.$setVue.$delete
Vue.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...
vue
vm.userProfilegetter
sourceKey_data, keyuserProfile, sharedPropertyDefinitionvue
gettervm["_data"]["userProfile"]name,vuegettersetter
vm.userProfilegetter
userProfilegetter
Object.assignvm.userProfile
vm.userProfilesetter
Object.assignvm.userProfilesetter
newValvalvue(NaN??)
setter
setter
1017
valvue
1019
observe(newVal)
observeobserver instance.
observer
this.walk
1
vue
https://codepen.io/rushui/ful...
setter
vue1004
userProfilesetter setter,
MDNObject.assign,?
Object.assign(target, ...sources)
Object.assign [[Get]][[Set]] getter setter
28userProfilenamegettersetteragevueagegettersetter, ageuserProfileuserProfilesetter
setter
28userProfilesetter
https://codepen.io/rushui/ful...
setter
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.