[Diccionario front-end] La reserva de conocimiento necesaria para aprender el código fuente de Vue

Prefacio

Actualmente estoy escribiendo contenido avanzado para Vue. Durante este proceso, algunas personas me preguntaron qué preparativos necesito para leer el código fuente de Vue. Entonces hay un artículo fuera de este plan.

Cuando desee aprender el código fuente de Vue, debe tener una base sólida de JavaScript.La siguiente lista es solo algunos de los puntos de conocimiento representativos. Si no tiene una base de JavaScript, se recomienda no apresurarse a leer el código fuente de Vue, por lo que se rendirá fácilmente.

Partiré de los siguientes 7 puntos:

  1. Sintaxis básica de flujo

  2. Modelo de publicación / suscripción

  3. Object.defineProperty

  4. Sintaxis de ES6 +

  5. Cadena prototipo, cierre

  6. Función Currying

  7. bucle de eventos

[Diccionario front-end] La reserva de conocimiento necesaria para aprender el código fuente de Vue

Reserva de conocimientos necesarios

Cabe señalar que cada punto de este artículo no se describirá en particular en detalle. Resumiré algunos de los puntos de conocimiento aquí. Cada punto detallado todavía necesita dedicar tiempo para aprender.

Sintaxis básica de flujo

Creo que cualquiera que haya visto el código fuente de Vue, Vuex, etc. sabe que usa herramientas de verificación de tipo estático Flow.

Sabemos que JavaScript es un lenguaje de escritura débil, por lo que somos propensos a problemas inesperados cuando escribimos código. Es precisamente por este problema que apareció Flow, una herramienta de verificación de tipo estática.

Esta herramienta puede cambiar la situación de que JavaScript es un lenguaje de escritura débil y puede agregar restricciones de tipo para mejorar la calidad del código.

// 未使用 Flow 限制

function sum(a, b) {

  return a + b;

}

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

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

  return a + b;

}

Tipo de detección básica

Flow admite tipos de datos primitivos, que son los siguientes:

boolean

number

string

null

void( 对应 undefined )

Al definir variables, declare tipos en lugares clave, utilizando lo siguiente:

let str:string = 'str';

// 重新赋值

str = 3  // 报错

Detección de tipo complejo

Flow admite la detección de tipos complejos, incluidos los siguientes:

Object

Array

Function

自定义的 Class

Debe tenerse en cuenta que al usar flow.js directamente, JavaScript no se puede ejecutar en el lado del navegador. Debe usar el complemento babel. El complemento babel-preset-flow-vue se usa en el código fuente de vue y se configura en babelrc.

La sintaxis detallada de Flow se puede ver en la siguiente información:

Aquí se recomiendan dos materiales

  1. Documento oficial: https://flow.org/en/

  2. Comenzando con Flow: https://zhuanlan.zhihu.com/p/26204569

Modelo de publicación / suscripción

Sabemos que Vue implementa un mecanismo de enlace bidireccional internamente, para que no tengamos que manipular el DOM como antes.

De hecho, el mecanismo de enlace bidireccional de Vue utiliza el secuestro de datos combinado con el modelo de publicación / suscripción para lograr: secuestrar el establecedor y el captador de cada propiedad a través de Object.defineProperty (), publicar un mensaje para el suscriptor cuando los datos cambian y activar la devolución de llamada del oyente correspondiente.

Descubrí que algunas personas confunden el modelo de observador con el modelo de publicación / suscripción. De hecho, el modelo de suscripción tiene un centro de distribución para la gestión unificada de eventos de suscripción. El modo de observador puede registrar y llamar eventos a voluntad.

Dibujé un diagrama de flujo general para ilustrar el modelo de observador y el modelo de publicación / suscripción. como sigue:
[Diccionario front-end] La reserva de conocimiento necesaria para aprender el código fuente de Vue

Hablaré de esto en detalle en el próximo artículo. Aquí hay un concepto primero. Si está interesado, puede encontrar la información usted mismo o esperar a que se publique mi artículo.

De hecho, estamos familiarizados con este patrón, pero es posible que usted no lo haya notado:

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

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

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

})

Puede pensar en un proceso de ejecución de enlace de eventos anterior, debería tener resonancia.

Función Currying

Conceptos básicos del enlace de datos bidireccional: Object.defineProperty ()

Uno, atributos de datos

El atributo de datos contiene la ubicación de un valor de datos. Esta posición puede leer y escribir valores. Las propiedades de datos tienen cuatro características que describen su comportamiento:
[Diccionario front-end] La reserva de conocimiento necesaria para aprender el código fuente de Vue
Si desea modificar las cuatro propiedades de datos predeterminadas anteriores, debe utilizar el método Object.defineProperty () de ECMAScript.

Este método contiene 3 parámetros: el objeto donde se encuentra el atributo, el nombre del atributo y el objeto descriptor. Los atributos del objeto descriptor deben estar en los 4 atributos anteriores.

var person = {

  name: '',

};

// 不能修改属性的值

Object.defineProperty(person, "name",{

    writable: false,

    value: "小生方勤"

});

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

person.name = "方勤";

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

Dos, propiedades de acceso

Las propiedades de accesor no contienen valores de datos, contienen un par de funciones getter y setter (no es obligatorio). Al leer y escribir el valor de una propiedad de acceso, se llaman las funciones getter y setter correspondientes, y nuestro vue agrega las operaciones que necesitamos a las funciones getter y setter.

Cabe señalar que [valor o escritura] no debe coexistir con [get o set].

Las propiedades de acceso tienen las siguientes 4 características:
[Diccionario front-end] La reserva de conocimiento necesaria para aprender el código fuente de Vue
Démosle un ejemplo:

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

Si no conoce el método Object.defineProperty () antes, le sugiero que lea las páginas 139-144 de "Programación avanzada de JavaScript".

Charla adicional sobre Object.create (nulo)

Podemos asignar valores como this.set = Object.create (null) en todas partes del código fuente. ¿Por qué hacer esto? La ventaja de escribir de esta manera es que no necesita considerar las propiedades en la cadena del prototipo y realmente puede crear un objeto puro.

En primer lugar, Object.create puede entenderse como heredar un objeto. Es una característica de ES5 y debe ser compatible con navegadores más antiguos. El código básico es el siguiente:

if (!Object.create) {

    Object.create = function (o) {

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

        F.prototype = o;

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

    };

}

Sintaxis de ES6 +

De hecho, esto debería ser algo que debes saber de forma predeterminada, pero como alguien me hizo algunas preguntas relacionadas antes, déjame hablar un poco sobre ello.
La diferencia entre exportdefault y export

  1. Puede haber varias exportaciones en un archivo o módulo, pero solo una exportación predeterminada

  2. Exportar mediante exportación, agregar {} al importar, pero exportdefault no necesita

    1.exportar

    //a.js

    export const str = "Xiaosheng Fangqin";

    //b.js

    import {str} from'a '; // se requieren llaves al importar

    2.exportación predeterminada

    //a.js

    const str = "Xiaosheng Fang Qin";

    exportar str predeterminado;

    //b.js

    import str from'a '; // no se necesitan llaves al importar

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

Función de flecha

Este ha tomado:

  1. La dirección de esto en la función de flecha es fija, es decir, la dirección cuando se define la función

  2. Esto en la función ordinaria cambia cuando apunta a, es decir, el punto en el que se usa la función

herencia de clases

La clase se puede heredar a través de la palabra clave extensions, que es mucho más clara y conveniente que la herencia de ES5 al modificar la cadena del prototipo.

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

La palabra clave super, donde representa el constructor de la clase principal, se utiliza para crear el objeto this de la clase principal.

  1. La subclase debe llamar al método super en el método constructor; de lo contrario, se informará un error al crear una instancia. Esto se debe a que la subclase no tiene su propio objeto this, sino que hereda el objeto this de la clase principal y luego lo procesa.

  2. Puede usar esta palabra clave solo después de llamar a super, de lo contrario, se informará un error. Esto se debe a que la construcción de la instancia de la subclase se basa en el procesamiento de la instancia de la superclase, y solo el método super puede devolver la instancia de la superclase.
`super` 虽然代表了父类 `A` 的构造函数,但是返回的是子类 `B` 的实例,即` super` 内部的 `this ` 指的是 `B`,因此 `super()` 在这里相当于 A.prototype.constructor.call(this)

La diferencia entre la herencia de implementación de ES5 y ES6

La esencia de la herencia de ES5 es crear un objeto de instancia de la subclase primero, y luego agregar el método de la clase principal a esto (Parent.apply (this)).
El mecanismo de herencia de ES6 es completamente diferente, la esencia es crear primero el objeto de instancia de la clase principal (por lo que el método super () debe llamarse primero) y luego usar el constructor de la subclase para modificarlo.

apoderado

Aquellos que conocen los últimos desarrollos sabrán que en la próxima versión de Vue, se usará proxy en lugar de Object.defineProperty para completar el secuestro de datos.

You Da dijo que esta nueva solución duplicará la velocidad de inicialización y reducirá a la mitad el uso de memoria.

Uso del objeto proxy:

var proxy = new Proxy(target, handler);

new Proxy () genera una instancia de Proxy. El parámetro de destino indica el objeto de destino que se va a interceptar y el parámetro de controlador también es un objeto para personalizar el comportamiento de la interceptación.

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

Además de obtener y configurar, el proxy puede interceptar hasta 13 operaciones.

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

Si no comprende ES6, le recomiendo el siguiente tutorial:

Introducción de Ruan Yifeng a ECMAScript 6: http://es6.ruanyifeng.com/

Cadena prototipo, cierre

Cadena de prototipos

Debido a que antes escribí deliberadamente un artículo para explicar la cadena de prototipos, no hablaré de ello aquí:

Cadena de prototipo: https://juejin.im/post/5c335940f265da610e804097

Cierre

Aquí primero puse una parte de la función once en el código fuente de Vue. Esta es la función de llamada de cierre como valor de retorno:

/**

 * 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)

    }

  }

}

El propósito de esta función es garantizar que la función solo se llame una vez.

¿Por qué solo se llama una vez? Porque después de que se completa la llamada a la función, su contexto de ejecución no se destruirá, por lo que el valor de la llamada sigue ahí.

¿Qué es exactamente un cierre? La explicación de "Programación avanzada de JavaScript" es:

Un cierre es una función que tiene acceso a una variable en el alcance de otra función. La forma común de crear un cierre es crear una función dentro de otra función.

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

Proporcione dos fragmentos de código. Si conoce sus resultados, entonces conoce los cierres:

// 第一段

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

Función Currying

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

Déjame hablar sobre una pregunta de entrevista que encontré antes:

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

En el momento de la entrevista, todavía no conocía el concepto de curry, así que no respondí. Más tarde aprendí que esto se puede resolver mediante la función de curado, a saber:

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;

        }

    }

}

Entonces, ¿qué tiene esto que ver con Vue? Por supuesto que está relacionado:

¿Escribimos juicios como este a menudo?

if( A ){

 // code

}else if( B ){

 // code

}

No hay nada de malo en este método de escritura, pero cuando se repite el mismo juicio. Esto es un poco inteligente. En este momento, el curado funcional puede ser útil.

Debido a que Vue puede ejecutarse en diferentes plataformas, también existirá el juicio anterior. Aquí, utilizando las características del curry, algunos parámetros se guardan por adelantado a través del método createPatchFunction para su reutilización.

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

export function createPatchFunction (backend) {

    // 省略好多代码

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

        // 省略好多代码

    }

}

bucle de eventos

Cuatro conceptos:

  1. Tareas sincrónicas: tareas que están en cola para su ejecución en el hilo principal. Solo se completa la tarea anterior antes de que se pueda ejecutar la siguiente.

  2. Tarea asincrónica: se refiere a una determinada tarea asincrónica que se puede ejecutar sin ingresar al hilo principal, la tarea ingresará al hilo principal para su ejecución

  3. macrotask: Los escenarios principales incluyen el bloque de código principal, setTimeout, setInterval, etc.

  4. microtask: Los escenarios principales incluyen Promise, process.nextTick, etc.

Ya hay muchos tutoriales en línea sobre este punto y, debido a problemas de espacio, no entraré en detalles aquí.

Recomendar un artículo, que es muy detallado:

Mecanismo de ejecución de JavaScript: https://juejin.im/post/59e85eebf265da430d571f89#heading-4

para resumir

Este artículo está aquí. Pero hay una cosa que debo decir. El posicionamiento de este artículo no es explicar todo el conocimiento en todos los aspectos. Esto es poco realista y no tengo tal habilidad.

Solo espero contarle un punto a través de este artículo. Si desea ver el código fuente, algunos conocimientos básicos de JavaScript deben ser sólidos, de lo contrario tendrá dificultades.

Que progreses todos los días.

Plan de salida de artículos relacionados con Vue

Recientemente, mis amigos siempre me han preguntado acerca de preguntas relacionadas con Vue, por lo que publicaré 9 artículos relacionados con Vue a continuación, con la esperanza de poder ayudarlo. Mantendré una actualización en 7 a 10 días.

  1. [Diccionario front-end] Vuex inyecta el proceso del ciclo de vida de Vue (completado)

  2. [Diccionario front-end] Análisis del principio Vue Responsive

  3. [Diccionario front-end] El proceso de parchear VNodes nuevos y antiguos

  4. [Diccionario front-end] Cómo desarrollar componentes funcionales y cargar npm

  5. [Diccionario front-end] Optimice su proyecto de Vue desde estos aspectos

  6. [Diccionario front-end] Hable sobre el desarrollo del enrutamiento front-end a partir del diseño de Vue-Router

  7. [Diccionario front-end] Cómo usar Webpack correctamente en el proyecto

  8. [Diccionario front-end] Procesamiento del servidor Vue

  9. [Diccionario front-end] Cómo elegir entre Axios y Fetch

Te sugiero que prestes atención a mi cuenta oficial, puedes recibir los últimos artículos lo antes posible.

[Diccionario front-end] La reserva de conocimiento necesaria para aprender el código fuente de Vue

Si desea unirse a la comunicación grupal, también puede agregar un robot inteligente para que lo atraiga automáticamente al grupo:

[Diccionario front-end] La reserva de conocimiento necesaria para aprender el código fuente de Vue

Siéntete libre de ser feliz

Supongo que te gusta

Origin blog.51cto.com/15077552/2596451
Recomendado
Clasificación