Vue bidirectional data binding principle


Front technical point

1. Array reduce() method
Application scenario: the initial value of the next operation depends on the return value of the last operation

  • Cumulative calculation of values
//All items of an array are accumulated
    const arr = [2,3,4,6,2,12,34,56]; 
    //General implementation scheme 
    let total = 0;
    arr.forEach((item) => {
        total += item;

    //The reduce method of array will cycle the current array, focusing on the "snowball" operation
    //Array Reduce (function, initial value)
    //Array Reduce ((result of last calculation, item item item of current cycle) = > {}, 0)
    //Const cumulative result = array Reduce ((result of last calculation, item item item of current cycle) = > {return result of last time + item item item of current cycle}, 0)
    const total2 = arr.reduce((val,item)=>{
        return val+ item;
  • Get the value of the object property in a chain

2. Publish subscribe mode

  1. Dep class
  • Responsible for dependency collection
  • First, there is an array dedicated to storing all subscription information
  • Secondly, it also provides a method to append subscription information to the array
  • Finally, a loop is provided, which triggers each subscription information in the array
    Note: as long as we re assign the value to the data in Vue, this assignment action will be monitored by Vue,
    Then Vue will notify each subscriber of the change of data,
    Next, subscribers (DOM elements) update their content based on the latest data
  1. Watcher class
  • Responsible for subscribing to some events

3. Use object Data hijacking with defineproperty()
1. Adoptionget()Hijack value operation
2. Adoptionset()Hijack assignment operation

//Define a method of data hijacking
    function Observe(obj){
        //This is the termination condition of recursion
        if(!obj || typeof obj!='object') return;
        //Through object Keys (obj) gets each attribute on the current obj
        Object.keys(obj).forEach((key) => {
            //The attribute value corresponding to the currently cycled key
            let value = obj[key];
            //The attribute value corresponding to the currently cycled key
            //You need to add getters and setters for the properties corresponding to the current key
                enumerable: true,
                configurable: true,
                    // console. Log ('someone got the value of ${key} ');
                    return value;
                    value = newVal;

Why can the method under the methods object obtain the attribute under data through this

//Attribute agent
   object.key((this.$data).forEach((key) => {
           enumerable: true,
           configurable: true,
               return this.$data[key];
               this.$data[key] = newValue;

Template compilation of HTML structure

//Method of template compilation for HTML structure
function Compile(el,vm){
    //Get El the corresponding DOM element
    vm.$el = document.querySelector(el);
    //Create document fragments to improve the performance of DOM operations
    const fragment = document.createDocumentFragment();
    while ((childNode = vm.$el.firstChild)){

    //Perform template compilation

   //Method responsible for compiling DOM template
    function replace(){
        //Define regular matching interpolation expressions
        const regMustache = /\{\{\s*(S+)\s*\}\}/

        //Prove that the current node node is a text child node and needs regular replacement
        if(node.nodeType === 3){
            //Note: the text sub node is also a DOM object. If you want to get the string content of the text sub node, you need to call the textcontent property to get it
            const text = node.textContent;
            const execResult = regMustache.exec(text);

                const value = execResult[1].split('.').reduce((newObj,k)=>newObj[k],vm);
                node.textContent = text.replace(regMustache,value)
            //Conditions for terminating recursion

        //The proof is not a text node, but may be a DOM element, which needs recursive processing
        node.childNodes.forEach((child) => replace(child));

Simplest publish subscribe

//The simplest publish subscribe mode

//Collect dependencies / collect subscribers
class Dep {
    //This sub array is used to store the information of all subscribers
    this.subs = [];
  //Add subscriber information to the sub array

//Method of issuing notice
  this.subs.forEach((watcher) => watcher.update());


//Subscriber's class

class Watcher{

  //The CB callback function records how the current watcher updates its text content
//However, only knowing how to update yourself is not enough. You must also get the latest data
//Therefore, it is also necessary to transfer the VM during the new watcher (because the VM stores the latest data)
//In addition, you also need to know which data in the VM is the data you need at present
//Therefore, the data name corresponding to the watcher must be specified during the new watcher period

    this.vm = vm;
    this.key = key;
    this.cb = cb;
  //The instance of watcher needs an update function so that the publisher can notify us to update

const w1 = new Watcher(() =>{
  console. Log ('I'm the first subscriber ')