Detailed description of VueJS data driver and dependency Tracking Analysis, detailed description of vuejs

Source: Internet
Author: User

Detailed description of VueJS data driver and dependency Tracking Analysis, detailed description of vuejs

A previous analysis on Vue data binding principles needs to be reviewed recently and sent to the essay by the way.

In the previous implementation of an Mvvm, we used setter to observe the model and bound all viewmodels on the interface to the model. When the model changes, update all viewmodels and render the new value to the interface. At the same time, the listening interface updates all input bound by v-model to the model through the addEventListener event to complete bidirectional binding.

However, in addition to defineProperty, the program is useless.

  1. No compilation node.
  2. No processing expression dependency.

Here I will solve the problem of expression dependency. I will introduce the vue template compilation in the next section.

Define getter & setter for Data

class Observer {  constructor(data) {    this._data = data;    this.walk(this._data);  }  walk(data) {    Object.keys(data).forEach((key) => { this.defineRective(data, key, data[key]) })  };  defineRective(vm, key, value) {    var self = this;    if (value && typeof value === "object") {      this.walk(value);    }    Object.defineProperty(vm, key, {      get: function() {        return value;      },      set: function(newVal) {        if (value != newVal) {          if (newVal && typeof newVal === "object") {            self.walk(newVal);          }          value = newVal;        }      }    })  }}module.exports = Observer;

In this way, getter and setter are added for each attribute. When the attribute is an object, it is recursively added.

Once the attribute value is obtained or assigned a value to the attribute, get or set is triggered. When set is triggered, that is, model changes, a message can be published to notify all viewModel updates.

DefineRective (vm, key, value) {// stores the dependency expression of this attribute in the closure. Var dep = new Dep (); var self = this; if (value & typeof value = "object") {this. walk (value);} Object. defineProperty (vm, key, {get: function () {return value;}, set: function (newVal) {if (value! = NewVal) {if (newVal & typeof newVal = "object") {self. walk (newVal);} value = newVal; // notify all viewmodels to update dep. notify ();}}})}

So how to define Dep ??

Class Dep {constructor () {// dependency list this. dependences = [];} // Add dependency addDep (watcher) {if (watcher) {this. dependences. push (watcher) ;}}// notify all dependencies to update notify () {this. dependences. forEach (watcher) => {watcher. update () ;}} module. exports = Dep;

Each dependency here is a Watcher.

See how to define Watcher

Each Watcher has a unique ID, which has an expression and a callback function.

For example, expression a + B will access expression a and expression B During get computing. Because JavaScript is a single thread, only one JavaScript code is executed at any time, dep.tar get is used as a global variable to represent the current Watcher expression. Then, access a, B Through compute, trigger getter of a and B, and add Dep.tar get as dependency in getter.

Once the set of a and B is triggered, the update function is called to update the dependent values.

Var uid = 0; class Watcher {constructor (viewModel, exp, callback) {this. viewModel = viewModel; this. id = uid ++; this. exp = exp; this. callback = callback; this. oldValue = ""; this. update ();} get () {Dep.tar get = this; var res = this. compute (this. viewModel, this. exp); Dep.tar get = null; return res;} update () {var newValue = this. get (); if (this. oldValue = newValue) {return;} // update Dom in callback this. callback (newValue, this. oldValue); this. oldValue = newValue;} compute (viewModel, exp) {var res = replaceWith (viewModel, exp); return res ;}} module. exports = Watcher;

Because the current expression needs to be executed under the current model, replaceWith function is used to replace with. For details, refer to the alternative Syntax of with in another article in javascript.

Add dependency through get

Object.defineProperty(vm, key, {  get: function() {    var watcher = Dep.target;    if (watcher && !dep.dependences[watcher.id]) {      dep.addDep(watcher);    }    return value;  },  set: function(newVal) {    if (value != newVal) {      if (newVal && typeof newVal === "object") {        self.walk(newVal);      }      value = newVal;      dep.notify();    }  }})

This method of adding dependencies is too clever.

Here I drew a picture to describe it.

Finally, let's test the code.

const Observer = require('./Observer.js');const Watcher = require('./watcher.js');var data = {  a: 10,  b: {    c: 5,    d: {      e: 20,    }  }}var observe = new Observer(data);var watcher = new Watcher(data, "a+b.c", function(newValue, oldValue) {  console.log("new value is " + newValue);  console.log("oldValue is " + oldValue);});console.log("\r\n");console.log("a has changed to 50,then the expr should has value 55");data.a = 50;console.log("\r\n");console.log("b.c has changed to 50,then the expr should has value 122");data.b.c = 72;;console.log("\r\n");console.log("b.c has reseted an object,then the expr should has value 80");data.b = { c: 30 }

OK

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.