introduce
Vue updates view data by listening for collected dependencies through getters/setters of Object.defineProperty, notifying changes when properties are accessed and modified;
Restricted by modern JavaScript (and deprecated Object.Observe), Vue cannot detect additions or deletions of Object attributes. Since Vue performs getter/setter conversion procedures on the property when initializing the instance, the property must exist on options’ data object for Vue to convert it so that it is responsive.
getter/setter
The getter: get syntax binds an object property to the function that will be called when the property is queried.
Setter: When you try to set a property, the set syntax binds the object property to the function to be called.
Object.defineProperty
The object.defineProperty () method directly defines a new property on an Object, or modifies an existing property of an Object, and returns the Object.
What does Vue do?
Let’s start with some code:
let data0 = {
n: 0
}
// Define n with object.defineProperty
let data1 = {}
Object.defineProperty(data1, 'n', {
value: 0
})
console.log('Requirement 1:${data1.n}`)
// Summary: This grammar is making things complicated. No, keep looking.
// N cannot be less than 0
// that is, data2.n = -1 should be invalid, but data2.n = 1 is valid
let data2 = {}
data2._n = 0 // _n is used to secretly store n values
Object.defineProperty(data2, 'n', {
get(){
return this._n
},
set(value){
if(value < 0) return
this._n = value
}
})
console.log('Demand two:${data2.n}`)
data2.n = -1
console.log('Demand two:${data2.n}Set to -1 fail ')
data2.n = 1
console.log('Demand two:${data2.n}Set to 1 success ')
// What if the other side uses datA2._n directly?
/ / you are malicious
// Requirement 3: Use the proxy
let data3 = proxy({ data: {n:0}})// The parentheses are anonymous objects that cannot be accessed
function proxy({data}/ * deconstruction assignment, don't old q * / TM){
const obj = {}
// The 'n' is dead, so in theory you should iterate over all the keys of data
// Because I'm afraid you don't understand
Object.defineProperty(obj, 'n', {
get(){
return data.n
},
set(value){
if(value<0)return
data.n = value
}
})
return obj // obj is the proxy
}
// data3 就是 obj
console.log(Requirement 3:${data3.n}`)
data3.n = -1
console.log(Requirement 3:${data3.n}, set to -1 failure ')
data3.n = 1
console.log(Requirement 3:${data3.n}, set to 1 success ')
// Do you have anything to say?
// Yes! Look at the code below
/ / need four
let myData = {n:0}
let data4 = proxy({ data:myData }) // The parentheses are anonymous objects that cannot be accessed
// data3 就是 obj
console.log(` bar:${data4.n}`)
myData.n = -1
console.log(` bar:${data4.n}, set to -1 failed! ? `)
// If I change myData now, can I change it? ! You nai I what
// Fuck it, you really mean it
// Requirement 5: Intercept users even if they modify myData
let myData5 = {n:0}
let data5 = proxy2({ data:myData5 }) // The parentheses are anonymous objects that cannot be accessed
// vm = new Vue({data: {... }}) //
function proxy2({data}/* Destruct assignment */){
// The 'n' is dead, so in theory you should iterate over all the keys of data
let value = data.n
Object.defineProperty(data, 'n', {
get(){
return value
},
set(newValue){
if(newValue<0)return
value = newValue
}
})
// Add the above sentence, this sentence will listen to data
const obj = {}
Object.defineProperty(obj, 'n', {
get(){
return data.n
},
set(value){
if(value<0)return// This sentence is redundant
data.n = value
}
})
return obj
// This code adds the proxy function to data. Obj is the proxy
}
// data3 就是 obj
console.log('Requirement 5:${data5.n}`)
myData5.n = -1
console.log('Requirement 5:${data5.n}, set to -1 failed ')
myData5.n = 1
console.log('Requirement 5:${data5.n}, set to 1 successfully)
// Does this code look familiar?
// let data5 = proxy2({ data:myData5 })
// let vm = new Vue({data: myData})
// Now we can say what new Vue does
Copy the code
So we now know that Vue does two things when it initializes:
- Make the VM a proxy for Data
- Listen on all properties of data
At this point, the Vue can respond to any changes to the data, and the Vue helps us re-render the UI when the data changes in response, i.e. the render process.
Some problems with Vue listening for data
If you use it undeclared, Vue will issue a warning on the console
new Vue({
data: {},
template: `
{{n}}
`
}).$mount("#app");
Copy the code
However, if written like this, there is no warning, and you can see that Vue only checks the first level properties
new Vue({
data: {
obj: {
a: 0}},template: `
{{obj.b}}
`.methods: {
setB() {
this.obj.b = 1;
}
}
}).$mount("#app");
Copy the code
In order to solve the problem that new attributes do not listen, Vue provides a vue. set method to add attribute listening
Vue.set(this.obj, 'b'.1)
// or this.$set
Copy the code
Vue 3 realization of responsivity principle
Since Vue 2 cannot detect the addition or deletion of object attributes, the reactive part of Vue 3 is rebased on Proxy’s Observer implementation, which provides the full range of responsiveness capabilities that override languages (JavaScript). Eliminates some limitations that currently exist in Vue 2 with Object.defineProperty. These limitations include:
- Monitoring the addition and deletion of attributes;
- The array based on subscript modification, the. Length modification monitoring;
- Support for Map, Set, WeakMap and WeakSet;
Proxy
Proxy objects are used to create a Proxy for an object to intercept and customize basic operations (such as property lookup, assignment, enumeration, function calls, and so on).
How does Vue 3 establish responsiveness
There are two ways to establish the response formula of Vue 3:
- The first one is using the Composition API
reactive
Build responsiveness directly - The second one is the traditional one
options: {data: return {}}
In the form of