As a front-end architecture developed by Chinese programmer You Yuxi, its origin has brought great glory to Chinese people. More importantly, Vue is easier to use than other front-end frameworks, can be integrated with third-party libraries or existing projects, and can provide drivers for single-page applications.


Current industry slang: not Vue’s front end is not a qualified front end engineer!


The core of vue.js responsiveness is the use of ES5 object.defineProperty, which is why vue.js is not compatible with IE8 and below. Let’s have a visual understanding of it.


Object.defineProperty


The object.defineProperty method directly defines a new attribute on an Object, or modifies an existing attribute of an Object, and returns the Object.



Obj is the object on which attributes are to be defined; Prop is the name of the property to be defined or modified; Descriptor is the property descriptor to be defined or modified.


The core descriptor is descriptor, which has a bunch of optional key values, and you can refer to its documentation for details. Here we care most about get and set. Get is a getter method for a property that fires when it is accessed; Set is a setter method for a property that is triggered when we make changes to that property.


Once an object has a getter and setter, we can simply call it a reactive object. So vue.js has turned which objects into responsive objects? Next, we analyze them from the source level.


initState


In the Vue initialization phase, _init method performs, executes initState (vm) method, it is defined in SRC/core/instance/state. Js.



The initState method initializes properties such as props, methods, data, computed, and wathcer. Here we focus on props and data, and we’ll look at initialization of other properties in more detail later.


initProps



The main process of initialization of props is to traverse the defined props configuration. The traversal process does two things: one is to call defineReactive to change the value of each prop to reactive, and the corresponding properties in the props can be accessed via vm._props. The defineReactive method is covered later; The other is to proxy access to vm._props. XXX on vm. XXX, which we’ll cover later.


initData



The main process of data initialization is also to do two things, one is to define the data function to return the object traversal, proxy each value vm._data. XXX proxy to vm. The other is to call the observe method to observe the change of the entire data and make data responsive. You can access the corresponding property in the data return function by using vm._data. XXX. Observe will be introduced later.


As you can see, the initialization of both props and data is to turn them into reactive objects. We’ve touched on a couple of functions in this process, and we’ll look at them in detail.


proxy


The purpose of the proxy is to prop properties on props and data to the VM instance. That’s why, for example, if we define the following props, we can access it through the VM instance.



MSG we can access the MSG we defined in props in the say function via this. MSG. This happens in the proxy phase:



The implementation of the proxy method is simple. The target[sourceKey][key] read/write is changed to target[key] read/write via Object.defineProperty. So for props, the read/write to vm._props. XXX becomes the read/write to vm. XXX, and for vM. _props. So we can access the XXX property defined in props through vm. XXX.


Similarly, for data, reads and writes to vm._data.xxxx become reads and writes to vm.xxxx, and for vm._data.xxxx we have access to properties defined in the object returned by the data function, So we can use vm. XXXX to access the XXXX property defined in the data function return object.


Observe function is used to the change of the monitoring data, it is defined in SRC/core/observer/index in js:



The observe method adds an Observer to a non-VNode object. If an Observer has been added, return it. Otherwise, instantiate an Observer if certain conditions are met. Let’s look at the Observer in action.


Observer


An Observer is a class that adds getters and setters to properties of an object for dependency collection and distribution of updates:



The Observer constructor logic is simple: first instantiate the Dep object, which will be described later, and then add an instance of itself to the __ob__ attribute of the value of the data object by executing def. Def is defined in SRC /core/util/lang.js:



The def function is a very simple wrapper around Object.defineProperty, which is why WHEN I output the Object type on data during development, I find that the Object has an extra __ob__ attribute.

Returning to the Observer constructor, value is evaluated, observeArray is called for arrays, and walk is called for pure objects otherwise. ObserveArray iterates through the array and calls observe again. Walk iterates through the key of the object and calls defineReactive.


defineReactive


DefineReactive object function is to define a response type, add getter and setter to dynamic objects, it is defined in SRC/core/observer/index. In js:



DefineReactive initializes an instance of the Dep object, retrieves obJ’s property descriptor, and then recursively calls the Observe method on the child. This ensures that all of obJ’s child properties can become responsive objects, no matter how complex obJ’s structure is. This allows us to access or modify a deeply nested property in OBj and also trigger getters and setters. Finally, use Object.defineProperty to add getters and setters to obj’s property key. And the actual implementation of getters and setters, we’ll talk about later.


conclusion


In this section we introduce reactive objects. The core is to add getters and setters to data using Object.defineProperty. The purpose is to automatically execute some logic when we access data and write data: What a getter does is it depends on a collection, what a setter does is it sends out updates.