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:

  1. Make the VM a proxy for Data
  2. 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:

  1. Monitoring the addition and deletion of attributes;
  2. The array based on subscript modification, the. Length modification monitoring;
  3. 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 APIreactiveBuild responsiveness directly
  • The second one is the traditional oneoptions: {data: return {}}In the form of

reactive