preface

  • Article ideas article and implement article 】 【 】, in this paper, for the realization of the article, Suggestions to see two Windows synchronous read, or please read – “vue2.0 | idea | data hijacking
  • The first and second stages are framework building, and the code is shown in the Thinking section

The third stage: realize preliminary data hijacking, monitor user’s assignment and value operation of object attributes, and trigger the simultaneous execution of custom logic

Define the observe method, whose argument is an object. Non-objects return directly. The Observe object creates an Observe instance that performs recursive operations in the construct

observe/index.js
export function observe(data){
    console.log(data);
    if(typeofdata ! = ='object'&& data ! = =null) {return;
    }
    return new Observer(data);
}
Copy the code
class Observer {
    constructor(value){
       
        this.walk(value);
    }
    walk(data){
        let keys = Object.keys(data);
        keys.forEach(key= >{ defineReactuve(data,key,data[key]); }}})function defineReactuve(data,key,value){
    // implement recursion
    observe(value)
    Object.defineProperty(data,key,{
        get(){
            console.log('User value');
            return value
        },
        set(newValue){
            console.log('User assignment');
            if(value ! == newValue){// The new value is also monitored in set: the newly assigned object is observed
                observe(newValue);
                value = newValue
            }
        }
    }
    )
}
Copy the code
state.js
function initData(vm) {
    let data = vm.$options.data;
    vm._data = data = typeof data == 'function' ? data.call(vm) : data;
    observe(data);
}
Copy the code

Stage 4: Array data hijacking

Instead of traversing the properties of the array, the method of function hijacking is used to carry out the hijacking of the array, that is, rewriting the prototype of the array will rewrite its own seven methods, and traversing the elements of the object in the number group for deep observation, so as to realize the array listening;

Hijacking of objects in an array

The observation method is called to iterate over the elements that are objects in the array
observer/array.js
class Observer {
    constructor(data){

        if (Array.isArray(data)) {
            // Add a property to declare that the property has been observed
            Object.defineProperty(data,"__ob__", {enumerable:false.configurable: false.value:this
            })

            // Only array methods can be intercepted, but each item in the array cannot be listened to
            data.__proto__ = arrayMethods;
            this.observerArray(data)
            // console.log(data,arrayMethods);

        } else {
            this.walk(data)
        }
    }
    walk(data){
        let keys = Object.keys(data);
        keys.forEach(key= >{ defineReactuve(data,key,data[key]); })}observerArray(value) {
        for (let i  = 0; i < value.length; i++) {
            observe(value[i])
        }
    }
}
function defineReactuve(data,key,value){
    // implement recursion
    observe(value)
    Object.defineProperty(data,key,{
        get(){
            console.log('User value');
            return value
        },
        set(newValue){
            console.log('User assignment');
            if(value ! == newValue){// Observe the newly assigned object
                observe(newValue);
                value = newValue
            }
        }
    }
    )
Copy the code

Hijacking of array methods

Get the array prototype, override the seven methods, and export this object
observer/array.js
import { observe } from "./index.js";

// Intercept user call push Shift unshift pop reverse sort splice
// Get the array prototype
let oldArrayProtoMethods = Array.prototype;
// Override seven methods to export this new prototype object
export let arrayMethods = Object.create(oldArrayProtoMethods);

let methods = ['push'.'shift'.'unshift'.'pop'.'reverse'.'sort'.'splice'];


methods.forEach(method= >{
    // console.log(arrayMethods,method);

    arrayMethods[method] = function (. args){
        let r = oldArrayProtoMethods[method].apply(this,args)

        // todo
        let inserted;
        let ob = this.__ob__;
        switch (method) {
            case 'push':
            case 'unshift':
                inserted = args;break;
            case "splice":
                inserted = args.slice(2)
            default:
                break;
        }
        console.log('Array update method == to render the page');
        returnr; }})Copy the code
In the Observer construct, the prototype of the data is executed as a custom object if the data is observerArray
observer/index.js
class Observer {
    constructor(data){

        if (Array.isArray(data)) {
            // Add a property to declare that the property has been observed
            Object.defineProperty(data,"__ob__", {enumerable:false.configurable: false.value:this
            })

            // Only array methods can be intercepted, but each item in the array cannot be listened to
            data.__proto__ = arrayMethods;
            this.observerArray(data)
            // console.log(data,arrayMethods);

        } else {
            this.walk(data)
        }
    }
    walk(data){
        let keys = Object.keys(data);
        keys.forEach(key= >{ defineReactuve(data,key,data[key]); })}observerArray(value) {
        for (let i  = 0; i < value.length; i++) {
            observe(value[i])
        }
    }
}
function defineReactuve(data,key,value){
    // implement recursion
    observe(value)
    Object.defineProperty(data,key,{
        get(){
            console.log('User value');
            return value
        },
        set(newValue){
            console.log('User assignment');
            if(value ! == newValue){// Observe the newly assigned object
                observe(newValue);
                value = newValue
            }
        }
    }
    )
}
Copy the code
Methods with new functions are processed, and new value-added is observed and processed
observer/array.js
methods.forEach(method= >{
    arrayMethods[method] = function (. args){
        let r = oldArrayProtoMethods[method].apply(this,args)

        // Save the new element as an array
        let inserted;
        // Assign a value to __ob__ in the construction of an Observer class, 1. Declare that the corresponding attribute has been observed. 2. Make the observerArray method on the Observer class available here
        let ob = this.__ob__;
        switch (method) {
            case 'push':
            case 'unshift':
                inserted = args;break;
            case "splice":
                inserted = args.slice(2)
            default:
                break;
        }
		// If the array of new elements exists, the array is observed
        if(inserted) ob.observerArray(inserted)
        console.log('Array update method == to render the page');
        returnr; }})Copy the code

Stage 5: Small optimizations where agents allow users to process data directly from the VM

A layer of proxy via Object.defineProperty iterates over _data and defines getSet on all keys on the VM so that when the user assigns a value it is the _data operation

state.js
function proxy(vm,data,key) {
    Object.defineProperty(vm,key,{
        get(){
            return vm[data][key];
        },
        set(newValue){ vm[data][key] = newValue; }})}function initData(vm) {
    let data = vm.$options.data;
    vm._data = data = typeof data == 'function' ? data.call(vm) : data;

    // Perform the proxy to handle data directly from the instance
    for (const key in data) {
       proxy(vm,'_data',key)
    }

    observe(data);
}
Copy the code

Finally realize

  • Warehouse address: [email protected]: Sympath/blingSpace. Git
  • Direct access address: github.com/Sympath/bli…