Part.0 Concept cognition

At the beginning of the article, some concepts related to Vue are mentioned, such as:

  • Mvvm
  • Two-way binding
  • Data driven

Some features of Vue can be summarized, and the meanings of these words can be roughly summarized as follows: When we use Vue, we can focus on the view, we can focus on the data, we don’t have to worry about the complicated relationship between the data and the view, because Vue helps us do these intermediate operations in a much more efficient way, and these time-consuming intermediate operations, which I’m going to call Dom manipulation.

So in a nutshell,

“Vue helps us avoid direct Dom manipulation.”

Why avoid Dom manipulation directly in Part.1?

So I think there are two reasons for avoiding Dom manipulation:

For the development process:

Manipulating the Dom directly takes a lot of time and effort. As anyone who has worked with jQuery knows, we often use jQuery’s various selectors and Dom methods to navigate through layers of nested tags to fetch data, update data, and update views

According to the development results:

Complex Dom operations on a page can cause a lot of redrawing and reordering, which can seriously affect the performance of the page

So I think the core role of Vue in the project can be summed up in two points:

1. Help us update the view and improve development efficiency

2. Help us update views in smarter ways to improve page performance

Part.2 How does Vue do this?

At this point, regarding the internal implementation of Vue,

I skimmed through some information on the Internet and roughly extracted the following concepts:

  • Responsive system
  • Template compilation
  • Virtual dom
  • The diff algorithm

Reactive systems are more likely to help us update the view, and because of these principles, Vue knows when to update the view

The virtual DOM and the Diff algorithm are an advanced way to update your view to maximize performance

This article only focuses on responsive systems.

Part.3 Principle of responsive system

What exactly is “response”? What I understand is that Vue responds to data changes

When the data changes, we need to solve two problems:

  1. And we want to know which value has changed?
  2. When this value changes, what other values that depend on this value need to change as well?

Before we solve these two problems, let’s look at one method: Object.defineProperty()

We all know that an object can have many properties, and that each property has different properties, such as whether it can be enumerated, whether it can be modified, and so on

The object.defineProperty () method can be used to set these properties as follows


Object.defineProperty(obj, prop, descriptor)

// This method takes three arguments:

// obj: Object Specifies the target Object

// prop: String Target properties

// Descriptor: Object Feature Object

// Descriptor contains the following features to set

	// Enumerable: Boolean specifies whether the attribute is enumerable. The default is true
	// Signals: Boolean Specifies whether the property can be modified or deleted. The default is true
	// get: Function The method called to get the attribute
	// set: Function calls the method when setting the property
	// ...


// The following example briefly demonstrates the use of this method

// Declare an object
var a = {
    name: 'miaogang'
}

// use the propertyIsEnumerable() method to check that the newly declared propertyIsEnumerable by default
a.propertyIsEnumerable('name')  // true 

// Make it non-enumerable with the object.defineProperty () method
Object.defineProperty(a, 'name', {
    enumerable: false
})

// The setting takes effect
a.propertyIsEnumerable('name')  // false

// Enumerable affects object.keys (), for.. The result of syntax such as in
Copy the code

Now that we understand how ** object.defineProperty ()** is used, we move on to responsive systems.

In a responsive system, two properties of attributes are needed: set methods /get methods

To solve the two problems we need to solve to achieve responsive systems:

1. We need to know which value has changed?

2. When this value changes, what other values that depend on it need to change as well?

When the set method of a property is called, we know that the value of the property has been changed, and Vue updates the view to complete the response to the change.

When a property of the get method is called, means that there are other properties [dependent on] in this property, then we will record the dependencies, so when this attribute is changed, all [dependent on] in this property to other properties will change accordingly, the track of the dependencies between attributes like called “depend on the collection” the process of

Part.4 Code implementation of responsive system

To make the code easier to understand, let’s leave out the dependency collection part

Vue internally implements a **defineReactive()** method for reactivity of data.

The **defineReactive()** method implements the following:

function defineReactive (obj, key, val) {
    
    Object.defineProperty(obj, key, {
        enumerable: true.configurable: true.get: function reactiveGetter () {
            return val;         
        },
        set: function reactiveSetter (newVal) {
            // When an assignment is performed on a property, the property's get method is called
            // However, there is no need to update the view if the new value assigned to an attribute is equal to the previous value
            // So add a layer of judgment here to avoid unnecessary view updates
            if (newVal === val) return;
            val = newVal;
            cb(newVal);  // Update the view}}); }Copy the code

The **defineReactive()** method is used to reactone property of an object

Vue implements a **Observer()** method to batch all enumerable attributes of an object.

**Observer()**

function observer (value) {
    if(! value || (typeofvalue ! = ='object')) {
        return;
    }
    // object.keys () returns an array of the property names of all the enumerable properties of an Object
    Object.keys(value).forEach((key) = > {
        // Use defineReactive() to traverse each attribute
        defineReactive(value, key, value[key]);
    });
}
Copy the code
// When we create a new Vue instance, the Vue constructor does the following:
let o = new Vue({
    data: {
        test: "I am test."}})// The options we wrote are passed into the Vue constructor
class Vue {
    constructor(options) {
        this._data = options.data;
        // Vue then uses the Oberver () function to make the data in data responsive.
        observer(this._data); }}// This process is a simple demonstration of how a responsive system is built when Vue is initialized
// But this is just an intuitive example that is easy to understand and doesn't cover most real scenarios
// For example, the defineReactive() method should be called recursively to make the declared attribute in data and all its descendants reactive.
// Another example: the current defineReactive() method does not work with arrays, and additional processing is required when facing arrays
Copy the code

Part.5 Dependency collection in responsive systems

Dependency collection is implemented based on the observer/subscriber design pattern

Each of our reactive attributes is a subscriber, and every other attribute that depends on that attribute is an observer of that attribute

When a subscriber changes, all its observers are notified of the change

// Implement a subscriber Dep
class Dep {
    constructor () {
		// Each subscriber will have an array to store his observers
        this.subs = [];
    }
	// The method used to add an observer
    addSub (sub) {
        this.subs.push(sub);
    }
	// Notify all observers of view updates
    notify () {
        this.subs.forEach((sub) = >{ sub.update(); }}})// Implement an observer Watcher
class Watcher {
    constructor () {
        // Every time a new Watcher instance is created, the current instance itself is exposed
        Dep.target = this;
    }
    // Used to update views
    update () {
        console.log("View updated ~"); }}Copy the code

With the observer and subscriber implemented, let’s tweak the previous code

function defineReactive (obj, key, val) {
   	When processing each object, first instantiate a subscriber
    const dep = new Dep();
    
    Object.defineProperty(obj, key, {
        enumerable: true.configurable: true.get: function reactiveGetter () {
            // When there are other dependencies on this property, record this level of dependency
            dep.addSub(Dep.target);
            return val;         
        },
        set: function reactiveSetter (newVal) {
            if (newVal === val) return;
            dep.notify(); // When the property changes
            cb(newVal);  // Update the view}}); }class Vue {
    constructor(options) {
        this._data = options.data;
        observer(this._data);
        // Instantiate a Watcher object
        new Watcher();
        // Simulate the view's initial rendering
        console.log('render~'.this._data.test); }}Copy the code

Part.6 Practical application of responsive system

Vue official website document has the following sentence:

Since Vue does not allow you to add root-level reactive properties dynamically, you must declare root-level reactive properties, even if they are null, before initializing the instance

Example: JSFIDDLE

Resources: Analyze the internal workings of vue.js

Rookie front end, is not mature, deviation still hope to point out above

Mragon