• The mini-vue framework builds Part1 — the directory structure
  • The mini-vue framework builds Part3 — $Mount method implementation
  • Minivue framework builds Part4 — before Render

An overview of the

  • Implement the data broker using Object.defineProperty()
  • Overview of data broker implementation principles

Representative data model

  • Object nested object
  • Data model of Array type, and the Array built-in methods that change the proxy data when fired
    data: {
        name: "Xiao Ming".age: 10.address: "Home address".info: {
            IDCard: "Id Card No.".school: "School Name".obj: {
                name: "sddd"}},list: [{ a: 1.b: 2}}]Copy the code

Data broker implementation – Broker single data

    / * * *@param {*} Key requires the field of the proxy -- type string *@param {*} ProxyObj proxy Object -- Object type *@param {*} OriginObject The original data Object -- Object type *@returns* /
    function proxyKey(key, proxyObj, originObject) {
      Object.defineProperty(proxyObj, key, {
        configurable: true.// Allows you to add or delete the key of the proxy object
        get: function () {
          return originObject[key];
        },
        set: function (val) {
          return(originObject[key] = val); }});return proxyObj;
    }
   
   // Code practice
  const prpxyObj = {};
  let data = {
      a: 20.b: 30
  }
   window.test = proxyKey("a", prpxyObj, data)
Copy the code

Proxy array method

  • Objective: To modify the prototype chain of the array object, and to change the body of the array built-in methods, such as push method, pop method
  • Value property in object.defineProperty () : The value corresponding to the proxy property. It can be any valid JavaScript value (numeric value, object, function, etc.) that you can control to return.
    const arrProxyFunc = new Array(a);/** * obj: proxy object * proxyFunction: array method to be proxied */
    function proxyArrayFunctionCall(obj, proxyFunction) {
      Object.defineProperty(obj, proxyFunction, {
        enumerable: true.configurable: true.// Allow deleting the contents of proxy data
        value: function (. args) {
          // Map the method on the Array prototype chain,
          const arrProxyFunc = arrayProtoType[proxyFunction];
          // Change this pointer
          const result = arrProxyFunc.apply(this, args);
          returnresult; }}); }/** * array: the array method that needs to be propped -- its prototype chain will completely override */
    function proxyArray(array) {
       // Create a proxy object -- a new array prototype chain, completely overwriting the previous prototype chain
      const obj = {
        eleType: "Array".pop() {},
        push(){}};// Proxy custom methods
      proxyArrayFunctionCall(obj, "pop",); proxyArrayFunctionCall(obj,"push");

      /** * overrides the original prototype chain - this implements the array method proxy * completely overrides the original array chain, no longer supports the built-in array methods, can only use the obj object provided methods */
      array.__proto__ = obj;
      return array;
    }
    
    // Debug code
    const arr = [];
    window.arr = arr;
    window.test = proxyArray(arr);
    
Copy the code
  • As you can see, both the arR’s prototype chain has been modified so that we implement a proxy for the array’s built-in methods
  • We will use this point when implementing the data broker

Implement data broker in Vue framework

  • Implement object nested object data proxy:proxyObject()You can see snippets of code in the method
  • Implement data proxy of array type:proxyArray()
  • Namespace:getNameSpace()This method is used to ensure that the data source does not get an error in the case of nested objects. For example, test under obj object, proxynumThis key, the value of the original data should beobj.test.num. So, the namespace is a string when implementing its proxyobj.test
    let obj = {
        a: 10.test: {
            num: 20}}Copy the code
  • Object. GetOwnPropertyNames () : returns a specified by the Object of all its attributes of the attribute name (including not enumerated attribute but does not include Symbol value as the name of the attribute) consisting of an array.
  • We used it when we implemented the proxy array methodObject.getOwnPropertyNamesMap all the built-in methods on the array prototype chain.
/** * Data proxy */
    const arrayProtoType = new Array(a);function getNameSpace(nameSpace = null, key = null) {
      if(nameSpace && ! key) {return nameSpace;
      } else if(key && ! nameSpace) {return key;
      } else {
        return `${nameSpace}.${key}`; }}function getObjectKey(obj) {
      return Object.keys(obj);
    }

    / * * * *@param {*} Key requires the field * of the proxy@param {*} ProxyObj proxy object *@param {*} OriginObject Specifies the original data object *@returns* /
    function proxyKey(key, proxyObj, originObject) {
      Object.defineProperty(proxyObj, key, {
        configurable: true.get: function () {
          return originObject[key];
        },
        set: function (val) {
          return(originObject[key] = val); }});return proxyObj;
    }

    /** * proxy object *@param {} option
     * @returns* /
    function proxyObject(vm, option, nameSpace) {
      let proxyObj = {};
      const proxyAllKey = getObjectKey(option);
      for (let i = 0; i < proxyAllKey.length; i++) {
        const key = proxyAllKey[i];
        const val = option[key];

        proxyKey(key, proxyObj, option);

        Object nested object or array type
        if (val instanceof Object || val instanceof Array) {
          option[key] = constructorProxy(vm, val, getNameSpace(nameSpace, key)); }}return proxyObj;
    }

    /** * Proxy some built-in method on the Array prototype chain *@param {*} vm
     * @param {*} Obj // Proxy object *@param {*} ProxyFunction // Array methods that require proxies *@param {*} nameSpace* /
    function proxyArrayFunctionCall(vm, obj, proxyFunction, nameSpace) {
      Object.defineProperty(obj, proxyFunction, {
        enumerable: true.configurable: true.// Allow deleting the contents of proxy data
        value: function (. args) {
          const arrProxyFunc = arrayProtoType[proxyFunction];
          const result = arrProxyFunc.apply(this, args);
          returnresult; }}); }/** * proxy array -- overwrites the array object's original prototype chain * Purpose: Trigger the proxy object's pop, push... Method, which is the return value of value * in proxyArrayFunctionCall@param {*} vm
     * @param {*} array
     * @param {*} nameSpace* /
    function proxyArray(vm, array, nameSpace) {
      /** * Get the keys of all the built-in methods on the Array prototype chain. * /
      const arrayProtoTypeAllKey = Object.getOwnPropertyNames(
        arrayProtoType.__proto__
      );

      const obj = {
        eleType: "Array". arrayProtoTypeAllKey, }; arrayProtoTypeAllKey.forEach((functionName) = > {
        proxyArrayFunctionCall(vm, obj, functionName, nameSpace);
      });

      // Overwrite the original prototype chain -- thus implementing the array method proxy
      array.__proto__ = obj;
      return array;
    }

    function constructorProxy(vm, options, nameSpace = "") {
      let proxy = {};

      if (options instanceof Array) {
        proxy = new Array(options.length);

        for (let i = 0; i < options.length; i++) {
          if (options[i] instanceof Object) {
            proxy[i] = proxyObject(vm, options[i], nameSpace);
          } else {
            proxy[i] = proxyKey(options[i], {}, options[i]);
          }
        }

        proxy = proxyArray(vm, options, nameSpace);
      } else if (options instanceof Object) {
        proxy = proxyObject(vm, options, nameSpace);
      } else {
        throw new Error("Error");
      }
      return proxy;
    }
    export default constructorProxy;

Copy the code