[Front-end dictionary] The necessary knowledge reserve for learning Vue source code

Preface

I'm currently writing advanced content for Vue. During this process, some people asked me what preparations I need to read the Vue source code? So there is an article outside of this plan.

When you want to learn the Vue source code, you need to have a solid JavaScript foundation. The following list is only some of the representative knowledge points. If you don't have a JavaScript foundation, it is recommended not to rush to read the Vue source code, so you will easily give up.

I will start from the following 7 points:

  1. Flow basic syntax

  2. Publish/subscribe model

  3. Object.defineProperty

  4. ES6+ syntax

  5. Prototype chain, closure

  6. Function Currying

  7. event loop

[Front-end dictionary] The necessary knowledge reserve for learning Vue source code

Necessary knowledge reserve

It should be noted that each point in this article will not be described in particular in detail. I will summarize some of the knowledge points here. Each detailed point still needs to spend time to learn.

Flow basic syntax

I believe anyone who has seen the source code of Vue, Vuex, etc. knows that they use Flow static type checking tools.

We know that JavaScript is a weakly typed language, so we are prone to unexpected problems when we write code. It is precisely because of this problem that Flow, a static type checking tool, appeared.

This tool can change the situation that JavaScript is a weakly typed language, and can add type restrictions to improve code quality.

// 未使用 Flow 限制

function sum(a, b) {

  return a + b;

}

// 使用 Flow 限制  a b 都是 number 类型。

function sum(a: number, b:number) {

  return a + b;

}

Basic detection type

Flow supports primitive data types, which are as follows:

boolean

number

string

null

void( 对应 undefined )

When defining variables, declare types in key places, using the following:

let str:string = 'str';

// 重新赋值

str = 3  // 报错

Complex type detection

Flow supports complex type detection, including the following:

Object

Array

Function

自定义的 Class

It should be noted that using flow.js directly, JavaScript cannot run on the browser side. You must use the babel plug-in. The babel-preset-flow-vue plug-in is used in the vue source code and configured in babelrc.

The detailed Flow syntax can be seen in the following information:

Two materials are recommended here

  1. Official document: https://flow.org/en/

  2. Getting started with Flow: https://zhuanlan.zhihu.com/p/26204569

Publish/subscribe model

We know that Vue implements a two-way binding mechanism internally, so that we don't have to manipulate the DOM as before.

In fact, Vue's two-way binding mechanism uses data hijacking combined with the publish/subscribe model to achieve: hijack the setter and getter of each property through Object.defineProperty(), publish a message to the subscriber when the data changes, and trigger the corresponding listener callback.

I found that some people confuse the observer model with the publish/subscribe model. In fact, the subscription model has a dispatch center for unified management of subscription events. The observer mode can register and call events at will.

I drew a general flow chart to illustrate the observer model and the publish/subscribe model. as follows:
[Front-end dictionary] The necessary knowledge reserve for learning Vue source code

I will talk about this in detail in the next article. Here is a concept first. If you are interested, you can find the information yourself, or wait for my article to be published.

In fact, we are familiar with this pattern, but you may not have noticed it yourself:

let div = document.getElementById('#div');

div.addEventListener('click', () => {

    console.log("div 被点击了一下")

})

You can think about a process of the above event binding execution, you should have resonance.

Function Currying

The basis of two-way data binding: Object.defineProperty()

One, data attributes

The data attribute contains the location of a data value. This position can read and write values. Data properties have four characteristics that describe their behavior:
[Front-end dictionary] The necessary knowledge reserve for learning Vue source code
If you want to modify the above four default data properties, you need to use ECMAScript's Object.defineProperty() method.

This method contains 3 parameters: the object where the attribute is located, the attribute name, and the descriptor object. The attributes of the descriptor object must be in the above 4 attributes.

var person = {

  name: '',

};

// 不能修改属性的值

Object.defineProperty(person, "name",{

    writable: false,

    value: "小生方勤"

});

console.log(person.name);   // "小生方勤"

person.name = "方勤";

console.log(person.name);  // "小生方勤"

Two, accessor properties

Accessor properties do not contain data values, they contain a pair of getter and setter functions (not required). When reading and writing the value of an accessor property, the corresponding getter and setter functions are called, and our vue adds the operations we need to the getter and setter functions.

It should be noted that [value or writable] must not coexist with [get or set].

Accessor properties have the following 4 characteristics:
[Front-end dictionary] The necessary knowledge reserve for learning Vue source code
Let’s give an example:

var person = {

    _name : "小生方勤"

};

Object.defineProperty(person, "name", {

    //注意 person 多定义了一个 name 属性

    set: function(value){

        this._name = "来自 setter : " + value;  

    },

    get: function(){

        return "来自 getter : " + this._name; 

    }

});

console.log( person.name );   // 来自 getter : 小生方勤

person.name = "XSFQ";        

console.log( person._name );  // 来自 setter : XSFQ

console.log( person.name );   // 来自 getter : 来自 setter : XSFQ

If you are not aware of the Object.defineProperty() method before, I suggest you read pages 139-144 of "JavaScript Advanced Programming".

Extra talk about Object.create(null)

We can assign values ​​like this.set=Object.create(null) everywhere in the source code. Why do this? The advantage of writing this way is that you don't need to consider the properties on the prototype chain, and you can really create a pure object.

First of all, Object.create can be understood as inheriting an object. It is a feature of ES5 and needs to be compatible with older browsers. The basic code is as follows:

if (!Object.create) {

    Object.create = function (o) {

        function F() {}     // 定义了一个隐式的构造函数

        F.prototype = o;

        return new F();     // 其实还是通过new来实现的

    };

}

ES6+ syntax

In fact, this should be something you need to know by default, but since someone asked me some related questions before, let me talk about it a little bit.
The difference between exportdefault and export

  1. There can be multiple exports in a file or module, but only one exportdefault

  2. Export through export, add {} when importing, but exportdefault does not need

    1.export

    //a.js

    export const str = "Xiaosheng Fangqin";

    //b.js

    import {str} from'a'; // curly braces are required when importing

    2.export default

    //a.js

    const str = "Xiaosheng Fang Qin";

    export default str;

    //b.js

    import str from'a'; // no need for curly braces when importing

exportdefaultconsta=1; 这样写是会报错的哟。

Arrow function

This one has taken:

  1. The direction of this in the arrow function is fixed, that is, the direction when the function is defined

  2. The this in the ordinary function changes when it points to, that is, the point when the function is used

class inheritance

Class can be inherited through the extends keyword, which is much clearer and more convenient than ES5's inheritance by modifying the prototype chain.

class staff { 

  constructor(){

    this.company = "ABC";    

    this.test = [1,2,3];

  }

  companyName(){

    return this.company; 

  }

}

class employee extends staff {

  constructor(name,profession){

    super();

    this.employeeName = name;

    this.profession = profession;

  }

}

// 将父类原型指向子类

let instanceOne = new employee("Andy", "A");

let instanceTwo = new employee("Rose", "B");

instanceOne.test.push(4);

// 测试 

console.log(instanceTwo.test);    // [1,2,3]

console.log(instanceOne.companyName()); // ABC

// 通过 Object.getPrototypeOf() 方法可以用来从子类上获取父类

console.log(Object.getPrototypeOf(employee) === staff)

// 通过 hasOwnProperty() 方法来确定自身属性与其原型属性

console.log(instanceOne.hasOwnProperty('test'))          // true

// 通过 isPrototypeOf() 方法来确定原型和实例的关系

console.log(staff.prototype.isPrototypeOf(instanceOne));    // true

The super keyword, where it represents the constructor of the parent class, is used to create the this object of the parent class.

  1. The subclass must call the super method in the constructor method, otherwise an error will be reported when creating an instance. This is because the subclass does not have its own this object, but inherits the this object of the parent class and then processes it.

  2. You can use this keyword only after calling super, otherwise an error will be reported. This is because the construction of the subclass instance is based on processing the superclass instance, and only the super method can return the superclass instance.
`super` 虽然代表了父类 `A` 的构造函数,但是返回的是子类 `B` 的实例,即` super` 内部的 `this ` 指的是 `B`,因此 `super()` 在这里相当于 A.prototype.constructor.call(this)

The difference between ES5 and ES6 implementation inheritance

The essence of ES5 inheritance is to first create the instance object this of the subclass, and then add the method of the parent class to this (Parent.apply(this)).
The inheritance mechanism of ES6 is completely different. The essence is to first create the instance object this of the parent class (so the super() method must be called first), and then use the constructor of the subclass to modify this.

proxy

Those who know the latest developments will know that in the next version of Vue, proxy will be used instead of Object.defineProperty to complete data hijacking.

You Da said that this new solution will double the initialization speed while halving the memory usage.

Usage of proxy object:

var proxy = new Proxy(target, handler);

new Proxy() generates a Proxy instance. The target parameter indicates the target object to be intercepted, and the handler parameter is also an object to customize the interception behavior.

var proxy = new Proxy({}, {

    get: function(obj, prop) {

        console.log('get 操作')

        return obj[prop];

    },

    set: function(obj, prop, value) {

        console.log('set 操作')

        obj[prop] = value;

    }

});

proxy.num = 2; // 设置 set 操作

console.log(proxy.num); // 设置 get 操作 // 2

In addition to get and set, proxy can intercept up to 13 operations.

注意,proxy 的最大问题在于浏览器支持度不够,IE 完全不兼容。

If you don’t understand ES6, I recommend the following tutorial:

Ruan Yifeng Introduction to ECMAScript 6: http://es6.ruanyifeng.com/

Prototype chain, closure

Prototype chain

Because I deliberately wrote an article to explain the prototype chain before, so I won’t talk about it here:

Prototype chain: https://juejin.im/post/5c335940f265da610e804097

Closure

Here I first put a piece of once function in the Vue source code. This is the closure call-the function as the return value:

/**

 * Ensure a function is called only once.

 */

export function once (fn: Function): Function {

  let called = false

  return function () {

    if (!called) {

      called = true

      fn.apply(this, arguments)

    }

  }

}

The purpose of this function is to ensure that the function is only called once.

Why is it only called once? Because after the function call is completed, its execution context will not be destroyed, so the value of called is still there.

What exactly is a closure? The explanation of "JavaScript Advanced Programming" is:

A closure is a function that has access to a variable in the scope of another function. The common way to create a closure is to create a function inside another function.

简单讲,闭包就是指有权访问另一个函数作用域中的变量的函数。

Give two pieces of code. If you know their results, then you know about closures:

// 第一段

var num = 20;

function fun(){

    var num = 10;

    return function con(){

        console.log( this.num )

    }

}

var funOne = fun();

funOne();  // 20

// 第二段

var num = 20;

function fun(){

    var num = 10;

    return function con(){

        console.log( num )

    }

}

var funOne = fun();

funOne(); // 10

Function Currying

所谓"柯里化",就是把一个多参数的函数,转化为单参数函数。

Let me talk about an interview question I encountered before:

如何使 add(2)(3)(4)() 输出 9

At the time of the interview, I still didn't know the concept of currying, so I didn't answer it. Later I learned that this can be solved by function currying, namely:

function add(num){

    var sum=0;

    sum= sum+num;

    return function tempFun(numB){

        if(arguments.length===0){

            return sum;

        }else{

            sum= sum+ numB;

            return tempFun;

        }

    }

}

So what does this have to do with Vue? Of course it is related:

Do we often write judgments like this?

if( A ){

 // code

}else if( B ){

 // code

}

There is nothing wrong with this writing method, but when the same judgment is repeated. This is a bit unintelligent. At this time, function currying can come in handy.

Because Vue can run on different platforms, the above judgment will also exist. Here, using the characteristics of currying, some parameters are saved in advance through the createPatchFunction method for reuse.

// 这样不用每次调用 patch 的时候都传递 nodeOps 和 modules

export function createPatchFunction (backend) {

    // 省略好多代码

    return function patch (oldVnode, vnode, hydrating, removeOnly) {

        // 省略好多代码

    }

}

event loop

Four concepts:

  1. Synchronous tasks: tasks that are queued for execution on the main thread. Only the previous task is completed before the next task can be executed

  2. Asynchronous task: Refers to a certain asynchronous task can be executed without entering the main thread, the task will enter the main thread for execution

  3. macrotask: The main scenarios include the main code block, setTimeout, setInterval, etc.

  4. microtask: The main scenarios include Promise, process.nextTick, etc.

There are already a lot of online tutorials on this point, and because of space issues, I won't go into details here.

Recommend an article, which is very detailed:

JavaScript execution mechanism: https://juejin.im/post/59e85eebf265da430d571f89#heading-4

to sum up

This article is over here. But there is one thing I need to say. The positioning of this article is not to explain all the knowledge in every aspect. This is unrealistic and I have no such ability.

I just hope to tell you a point through this article. If you want to see the source code, some essential JavaScript basic knowledge must be solid, otherwise you will struggle.

May you make progress every day.

Vue related articles output plan

Recently, friends have always asked me about Vue-related questions, so I will output 9 Vue-related articles next, hoping to help you. I will keep an update in 7 to 10 days.

  1. [Front-end dictionary] Vuex injects the Vue life cycle process (completed)

  2. [Front-end Dictionary] Analysis of Vue Responsive Principle

  3. [Front-end Dictionary] The process of patching new and old VNodes

  4. [Front-end dictionary] How to develop functional components and upload npm

  5. [Front-end dictionary] Optimize your Vue project from these aspects

  6. [Front-end Dictionary] Talk about the development of front-end routing from the Vue-Router design

  7. [Front-end dictionary] How to use Webpack correctly in the project

  8. [Front-end dictionary] Vue server rendering

  9. [Front-end dictionary] How to choose between Axios and Fetch

I suggest you pay attention to my official account, you can receive the latest articles as soon as possible.

[Front-end dictionary] The necessary knowledge reserve for learning Vue source code

If you want to join the group communication, you can also add a smart robot to automatically pull you into the group:

[Front-end dictionary] The necessary knowledge reserve for learning Vue source code

Feel free to be happy

Guess you like

Origin blog.51cto.com/15077552/2596451