This is the 7th day of my participation in Gwen Challenge

One, foreword

In the previous part, the realization of data proxy on Vue instance in the process of Vue data initialization was introduced. The core ideas are as follows:

  • Expose data on the vm._data instance property
  • Delegate the vm. XXX operation to vm._data using Object.defineProperty

In this paper, the current version of data hijacking and instance value proxy breakpoint debugging and process combing


Two, data hijacking

1. Debug the Demo

let vm = new Vue({
  el: '#app'.data() {
    return { 
      message: 'Hello Vue'./ / value
      obj: { key: "val" },      // Nested objects
      arr: [1.2.3]}              / / array}}); vm.message// Access properties
vm.arr.push(4) // Manipulate arrays
Copy the code

Ready to start breakpoint debugging:

Vue initialization entry

The Vue constructor, passing in the external options option, calls the prototype method _init to start the Vue initialization process

3. InitMixin method

Mount the _init method on the Vue prototype, taking the options option passed in when the Vue is initialized

The initMixin method does the following:

  • Initialization of data (multiple types of data: Data, props, Watch, computed…)
  • Once the data is initialized, render the data to the page

The vm $options:

  • $options = Vue; $options = Vue; $options = Vue;
  • Make methods in Vue easily accessible to options via the instance’s $options variable
  • Put options on the $options variable. Properties in options do not contaminate the VM instance

4. InitState method

InitState method: initializes state (in this case, state is data, which can come from multiple sources)

Currently, only data is processed. If options.data exists, go to initData to initialize data

5. InitData method

InitData method: initializes data

$options.data (Vue); $options.data (Vue);

Data can be a function or an object:

  • When data is a function: Call data to get the return value of the function – object, as the current instance data source data
  • When data is not a function: Data must be an object that serves directly as the instance data source

After this step of processing, data is processed as an object type for use by subsequent processes

Data = vm._data

  • The external instance VM cannot directly access the internal data attribute of the initData method.
  • In order to enable the external instance VM to access the data attribute directly, the _data instance attribute is added to the VM instance, that is, data = vm._data;
  • Data is an object, that is, a reference type, so data shares a reference with vm._data

6, Observe method (Observe entrance)

Observe Method: Data observation entry

After the observe is invoked, data is observed. Data is the responsive data

Data observation is deeply recursive. Observe is the entry point for data observation.

So, this is the first time the observe method is called, and value is the entire data root object;

  • If the value is not an object, the current processing is finished (in subsequent recursions, it means that the processing of this layer is finished and back to the previous layer);
  • If value is an object, create the data as an Observer instance; (The first call to observe creates the data root object as an Observer instance.)

7, with the Observer

In the constructor of the Observer class, the two cases where value is an array and an object are handled separately

Data hijacking – Object type:

  • Walk method: iterates through object attributes, calling defineReactive method for each attribute;
  • DefineReactive method: Add get and set methods to attributes via Object.defineProperty for data hijacking

Data hijacking – Array types:

  • Rewrite 7 prototype methods that change array data (e.g., splice, push, unshift)
  • The first time you enter Observer: value is the root data (which must be the object type), call the Walk method

8. Walk method

Walk: iterates through all (enumerable) attributes on the object, executing defineReactive in turn for data hijacking;

In the loop, add data hijacking for each of the three attributes in turn by calling defineReactive

The message:

Obj:

Arr:

DefineReactive method

DefineReactive is an external walk method for object attribute traversal, recursive call for each attribute; DefineReactive method: Creates Object. DefineProperty recursively for each attribute, which is a depth-first process

Deep observation data.message

Enter defineReactive method for the first time:

Obj = data root object, key = “messge”, value = string “Hello Vue”

Observe method first, perform deep recursive processing (depth first)

In the observe method, since the value of message is the string ‘Hello Vue’ and is not an object,

So instead of recursing down the path, return handles the Message property in data

In the defineReactive method:

Object.defineproperty on obj Object (first entry, obj is the root Object data)

Redefine the message property with the values GET and set

At this point, message processing is complete

Deep observation data.obJ

The second time, enter the defineReactive method:

{key: “val”}

Observe method first, perform deep recursive processing (depth first)

Since value is an object type {key: “val”}, the underlying layer needs to be handled recursively.

So, create value as an Observer instance

Within the Observer constructor, the object processing logic is performed, traversing all of the object’s properties through the Walk method

Continue to call the defineReactive method for each attribute and continue to do deep recursive observations

The walk method iterates through all the attributes of the data argument (value object {key: “val”}) and calls defineReactive to process the next layer:

The defineReactive method is called the first time:

Obj = object {key: “val”}, key = “key” value = “val”

In the observe method, since the key is the string ‘val’ and is not an object,

So, instead of recursing down, return handles the “key” property of the {key: “val”} object

Is the “key” attribute in the Object {key: “val”}, through object.defineProperty, to achieve the observation of the key attribute

{key: “val”} {key: “val”} {key: “val”} {key: “val”} {key: “val”

After executing the observe method, {key: “val”} deep observation of the internal properties of the object is complete

To continue the observation except for the {key: “val”} object, then the defineReactive method:

{key: “val”}

This completes the processing of obj

Deep observation data.arR

Third time, enter the defineReactive method:

Obj = data root object, key = “arr”, value = array [1,2,3]

Observe method first, perform deep recursive processing (depth first)

Since value is an array {key: “val”} (object type), the underlying layer needs to be processed recursively,

So, create value as an Observer instance

Value is an array type, we need to rewrite some of the array prototype methods:

Overriding the following seven methods is equivalent to intercepting an array update

Observe internally overwrites the array prototype method

The arR attribute of data is then processed with Object.defineProperty

In this way, the processing of ARR is completed, that is, the processing of the whole data is completed, and the observation of the data is completed

Complete data observation

The inner layer:

  • Array type: does not listen on every item of the array, only overwrites the array part of the prototype method;
  • Object type: Makes a deep observation of the properties of the object

Note: Since in recursive processing, objects will be deeply processed, so if there are objects in the array, the deep observation is also implemented;Copy the code

Third, data broker

1. Implement data proxy

To allow direct manipulation of the data on the instance, all attributes of the object are brokered once

Value proxy of VM instances: Proxy all vm. XXX value operations to vm._data. XXX

Proxy for three attributes in data:

1) Proxy message:

2) Agent OBJ:

3) Agent ARR

Implementation principle:

Add a layer of proxy for values and updates to vm._data using Object.defineProperty

2. The example value is vm.message

Because the proxy method proxies vm. XXX to vm._data.xxx via Object.defineProperty

So, when a value operation is performed through vm. XXX, the get method is entered and will be proxied to vm._data.xxx

Vm. _data. XXX triggers the get method on vm._data

Vm. message is proxied to vm[_data][message] for value, and the original message attribute is fetched through such a layer of proxiing.Copy the code

3. Array operation vm.arr.push

This will start with the vm.arr value operation, as above:

Because the proxy method proxies vm. XXX to vm._data.xxx via Object.defineProperty

Therefore, when a value operation is performed through vm. XXX, the get method is entered and is proxied to vm._data. XXX

[‘_data’].[‘arr’]

Vm.[‘_data’].[‘arr’] triggers the get method of vm._data

After fetching the arR array, call.push to manipulate the array:

At this point, we enter the array override push method:


Fourth, the current version of the problem analysis

1. Deep observation logic

The current version of the source code, to achieve the logic of deep observation is as follows:

  • Make a deep observation of the data root object
  • Properties inside data are observed recursively if they are objects
  • If the property inside data is an array, it overrides the methods on the array’s prototype chain (7)

2. Supported data observations

The current version supports the following data observations:

  • Data root objects (objects and nested objects implement deep observations)
  • Values in data (add get, set methods for attributes in objects)
  • Data in the array (rewrite the array prototype method, currently does not do recursive processing, only the realization of the array of single-layer hijacking)
  • Objects in data (objects and nested objects for deep observation)
  • The object of the object in data… (Objects and nested objects enable deep observation)
  • The value of the object in data (object and nested object deep observation, while adding get and set methods for the attributes in the object)

3. Unsupported data observations

The current version does not support the following data observations:

  • Data in the array of objects (rewrite the array prototype method, currently does not do recursive processing, only the realization of the array of single-layer hijacking)
  • Data in the array of the array in the array (rewrite the array prototype method, currently does not do recursive processing, only the realization of the array of single-layer hijacking)
  • New objects are not observed
  • The newly added array is not observed

4. Mechanism of Vue2 2.x

  • Changing the array subscript and length does not trigger an update (only overrides the array part of the prototype method); $set = vm.$set
  • The new attribute cannot be observed, and the update will not be triggered. $set = vm.$set

Four, the end

This article through Vue Demo breakpoint debugging, the current version of data hijacking and data proxy process combing

At the same time, compared with the functions provided by Vue2. X, the problems and shortcomings of the current version of data observation are analyzed

Next, a deeper look at arrays