This article is a vue. Js source code learning notes, suitable for vUE data response implementation have a certain understanding of the students, there are inaccurate statements in the article also hope to point out. So here we go

Note: the source code is marked in the appropriate location, easy to read

First, look at the source code for a computed implementation

/src/core/instance/state.js

// initState is executed on new Vue()export functionInitState (VM: Component) {/* other */ / perform initComputed if we define the comouted propertyif (opts.computed) initComputed(vm, opts.computed)
  /*
  	other
  */
}
Copy the code

Find the definition for initComputed in the same file

functionInitComputed (VM, computed) {// Add a _computedWatchers attribute to the component instance, Save all computed watcher const watchers = vm._computedWatchers = object.create (null) // Traverse all computed attributesfor (const key inConst userDef = computed[key] // We can define computed as a function or as an object {get:function() {},set:function(){}}
    const getter = typeof userDef === 'function'? userDef : UserDef. Get / / the watcher in the process of data response (note the second parameter is we just get the getter, remember), which [key] = new watcher (vm, getter | | it, / / attention here, pay attention to here, (**** knowledge getter) Noop, computedWatcherOptions)if(! (keyin vm)) {
      defineComputed(vm, key, userDef)
    } 
  }
}
Copy the code

Next we’ll find the defineComputed implementation in this file again

export functiondefineComputed (target, key, UserDef) {/ * other * / / / here I am to simplify/source/sharedPropertyDefinition is a global object / / get a get function sharedPropertyDefinition. Get = CreateComputedGetter (key) /* other */ / The main function of this function is to override object.defineProperty (target, key, sharedPropertyDefinition) }Copy the code

So createComputedGetter is important, important, important

functionCreateComputedGetter (key) {// Returns a function, which is the get function we used in the previous functionreturn function computedGetter() {// Get _computedWatchers const watcher = this._computedWatchers && that we added to the VM in initComputed This._computedwatchers [key] // If we define computed attributes, watcher must existif(watcher) {// Pay attention, pay attention, pay attention, as long as you use this computed property in your template, you cycle through each page updateif(watcher.dirty) {// ****标 题 : evaluate() // ****标 题 : evaluate()if(Dep., target) {/ / * * * * tags: knowledge point 3 watcher. Depend () / / * * * * sign: knowledge point 4}returnWatcher. Value // ****Copy the code

Second, computed attribute response

1. The Origin of everything

Again, we can find this object in this file

const computedWatcherOptions = { lazy: true }
Copy the code

Go back to new Watcher in initComputed

Which [key] = new Watcher (vm, getter | | it, it, computedWatcherOptions / / look here, look here, look here (incoming {lazy:true}))Copy the code
2. where it all began

Watcher of the source

constructor (vm, expOrFn, cb, options, isRenderWatcher) {
    this.vm = vm
    if(isRenderWatcher) { vm._watcher = this } vm._watchers.push(this) /* ... * /if(options) { this.lazy = !! options.lazy // this.lazy =true} this. Getter = expOrFn this. Dirty = this. Lazy initialization / / this. Dirty =true/ *... // this. Lazy is used when newtrueSo this value ='undefined'
    this.value = this.lazy ? undefined : this.get()
  }
Copy the code

The main flow is in the createComputedGetter function

  • innew Watcherwhenthis.dirty = this.lazysoWatcher. Dirty = true
  • Then,Knowledge point 2: watcher.evaluate()willthis.dirty = falseAnd then Watcher’s will be executedthis.get()Ultimately, it’s all about executionGetter:this.getter()
  • Continue toPoint 3:Dep.targetForever is true
  • Collect dependencies
  • Finally, get computed values

So much for the implementation of Watcher, this article is based on some knowledge of the Wathcer class. If you have the need to leave a message later will give you a detailed comb of the implementation process of the data response, there seems to be a lot of related articles on the Internet

3. Start the show
new Vue({
  data() {return {
      dataA: 'a',
      dataB: 'b'
    }
  },
  template: '<div>{{computedA}}-{{dataB}}</div>',
  computed: {
    computedA() {
      return 'computed ' + this.dataA
    }
  },
  method: {
      changeA(){
          this.dataA = 'change dataA'
      },
      changeB(){
          this.dataA = 'change dataB'}}})Copy the code

Look at createComputedGetter

  • 1. In the template when the page was first rendered{{computedA}}performcomputedA.get() Go to the function createComputedGetter
  • 2,1. this.dirty = true
  • 3,2.watcher.evaluate()On,this.dirty = false, Watcher executes internallyGetter:this.getter()
this.getter = computedA = function() {return 'computed'+ this.dataa // check here, check here, check hereCopy the code

We get Wacher. Value is equal to computed A

  • 4,watcher.depend()Recollect dependencies
  • 5. Return Wacher. value and render it to the page<div>computed a-b</div>
  • 6, we do this by callingthis.changA()Change dataA, call in dataAdep.notify()Will execute all watcher objects of dataAwathcer.update()Because theThe lazy of a computed watcher is always true.This. Dirty = true
  • 7, because dataA changes, trigger page re-render, re-render the template, in the template{{computedA}}Call againcomputedA.get(), loop step 1

Third, computed attribute caching

According to the computed response process in Paragraph 3 of Section 2, we know that computedA will listen for dataA changes to change knowledge point 1: this.dirty = true before finally executing the knowledge point getter

Assumptions:

  • We now executethis.changeB(), changes the dataB value,
  • All watcher objects of dataB will be executedwathcer.update().
  • Because the dataB has changed, it triggers the page to re-render, re-render the template, in the template{{computedA}}Call againcomputedA.get()Go to the function createComputedGetter.
  • becausecomputedADataB changes are not listened for and will not be executedcomputedAthewatcher.update()This. Dirty = false,It doesn’t work outGetter
  • Go straight back to last timeGetterThe results of thereturn watcher.value

conclusion

Because this article is mainly about computed knowledge, there is no detailed explanation about data response, which may seem a little confused. Later, it is necessary to analyze the realization process of VUE data response in detail.