Teach you Vue's dependency collection by hand

const data = {
    
    
  flag: true,
  firstName: "z",
  lastName: "ym"
}

const computed = {
    
    
  fullName() {
    
    
    if (!data.flag) return "没有名字"
    return data.firstName + data.lastName
  }
}

We simulate the data and computed properties of vue, now we need to implement the following functions

  1. When flag is true, set the value of firstName or lastName or flag, and recalculate the value of fullName
  2. When the flag is false, set the value of firstName or lastName, the value of fullName will not be recalculated, only when the flag is set, the value of fullName will be recalculated

Think about it first, how to achieve it if you write it yourself?


First of all, when we want to modify the value of a certain attribute of data, update the attribute of comouted, then we must subscribe to their get and set methods

function observer(obj, key) {
    
    
  let value = obj[key]
  Object.defineProperty(obj, key, {
    
    
    get() {
    
    
      return value
    },
    set(newVal) {
    
    
      value = newVal
      // 在这里设置值的时候,重新调用 computed.fullName 的方法,从而更新 fullName 的值
      data.fullName = computed.fullName()
    }
  })
}

Object.keys(data).forEach(key => {
    
    
  observer(data, key)
})

At this time we will find a problem

We don't know which data attribute changes will update which computed attribute value, so we need to collect the corresponding dependencies

We first need to think about it, what dependencies does Dep collect?
Dep hopes to do some other things when a data attribute is modified, so we need to collect those things before set

First we create a Dep class to collect dependencies and distribute dependencies

class Dep {
    
    
  constructor() {
    
    
    this.subs = []
  }

  notify() {
    
    
    this.subs.forEach(sub => sub())
  }
}

Then we now need to do two things

  1. Add Dep instances to all data original attributes
  2. Collect dependencies when getting, and dispatch dependencies when setting

Since we want to collect dependencies when getting, we must know when the get of the attribute will be triggered

We assume that there is a vue template template

<template>
	<p>{
   
   { fullName }}</p>
</template>
  • During the rendering process of the page, the get method of the attribute data.fullName must be called
  • 而 data.fullName = computed.fullName()
  • Calling computed.fullName will trigger the get of flag, firstName, lastName
  • Then naturally when these get are triggered, they know that what needs to be collected is
    the dependency of data.fullName = computed.fullName()

Then, the complete code we got is as follows

const data = {
    
    
  flag: true,
  firstName: 'z',
  lastName: 'ym'
}

const computed = {
    
    
  fullName() {
    
    
    if (!data.flag) return '没有任何东西'
    return data.firstName + data.lastName
  }
}

class Dep {
    
    
  constructor() {
    
    
    this.subs = []
  }

  notify() {
    
    
    this.subs.forEach(sub => sub())
    this.subs = []
  }
}

let willCollectFunc = () => {
    
    
  data.fullName = computed.fullName()
}

function observer(obj, key) {
    
    
  let value = obj[key]
  const dep = new Dep()
  Object.defineProperty(obj, key, {
    
    
    get() {
    
    
      dep.subs.push(willCollectFunc)
      return value
    },
    set(newVal) {
    
    
      value = newVal
      dep.notify()
    }
  })
}

Object.keys(data).forEach(key => {
    
    
  observer(data, key)
})

data.fullName = computed.fullName()

console.log(data.fullName)
data.firstName = "h"
console.log(data.fullName)
data.flag = false
console.log(data.fullName)
data.firstName = "z"
console.log(data.fullName)

For more detailed content, you can read the article I wrote before. It was not well written before, so it is easier to understand if it is more basic
https://blog.csdn.net/weixin_42335036/article/details/109286637

Guess you like

Origin blog.csdn.net/weixin_42335036/article/details/124206121