Desde la definición hasta la ejecución, el motor JS hace mucho trabajo de inicialización en la capa de implementación. Por lo tanto, antes de aprender el mecanismo de trabajo del motor JS, necesitamos introducir varios conceptos relacionados: pila de entorno de ejecución, objetos globales, entorno de ejecución, objetos variables, objetos activos, alcance y alcance, etc. Estos conceptos son los componentes centrales del trabajo del motor JS. El propósito de este artículo no es explicarle cada concepto de forma aislada, sino analizarlo a través de una demostración simple, explicando los detalles del motor JS de la definición a la ejecución, y el papel que juegan estos conceptos en él.
var x = 1; // Definir una variable global xfunction a (y) {var x = 2; // Definir una función X de la variable local B (z) {// Defina una función interna b console.log (x+y+z); } retorno b; // devuelve una referencia a la función b} var c = a (1); // ejecutar A, return BC (1); // ejecutar la función bEsta demostración es un cierre, y el resultado de la ejecución es 4. A continuación analizaremos el mecanismo de trabajo del motor JS en tres etapas: inicialización global, función de ejecución A y función de ejecución B :
1. Inicialización global
Cuando el motor JS ingresa a un código ejecutable, debe completar las siguientes tres tareas de inicialización:
Primero, cree un objeto global (objeto global). Solo hay una copia global de este objeto, se puede acceder a sus propiedades en cualquier lugar y su existencia acompañará todo el ciclo de vida de la aplicación. Al crear un objeto global, los objetos JS de uso común como las matemáticas, la cadena, la fecha, el documento se usan como sus propiedades. Dado que no se puede acceder directamente a este objeto global directamente por su nombre, hay otra ventana de propiedad y señala la ventana a sí misma, de modo que se pueda acceder al objeto global a través de la ventana. La estructura general del uso de pseudocódigo para simular objetos globales es la siguiente:
// Crear un objeto global var globalObject = {Math: {}, String: {}, fecha: {}, documento: {}, // operación dom ... ventana: this // deja que el atributo de la ventana apunte a sí mismo}Luego, el motor JS necesita construir una pila de contexto de ejecución. Al mismo tiempo, también necesita crear un contexto de ejecución global EC y empujar este entorno de ejecución global EC en la pila de entorno de ejecución. La función de la pila de entorno de ejecución es garantizar que el programa pueda ejecutarse en el orden correcto. En JavaScript, cada función tiene su propio entorno de ejecución. Al ejecutar una función, el entorno de ejecución de la función se empujará a la parte superior de la pila de entorno de ejecución y obtendrá los derechos de ejecución. Cuando se ejecuta esta función, su entorno de ejecución se elimina desde la parte superior de la pila y el derecho de ejecución se devuelve al entorno de ejecución anterior. Utilizamos el pseudocódigo para simular la relación entre la pila de entorno de ejecución y la CE:
var Ecstack = []; // Definir una pila de entorno de ejecución, similar a la matriz var ec = {}; // Crear un espacio de ejecución, // La especificación ECMA-262 no define claramente la estructura de datos de la CE, puede entenderlo como una pieza de espacio asignada en la memoria Ecstack.push (EC); // Ingrese la función y presione el entorno de ejecución ECSTACK.POP (EC); // Después de que regresa la función, elimine el entorno de ejecuciónFinalmente, el motor JS también crea un objeto variable global (objeto varibale) VO asociado con EC y puntos VO al objeto global. VO no solo contiene las propiedades originales del objeto global, sino que también incluye la variable x y la función A de la vida a nivel mundial. Al mismo tiempo, al definir la función A, también se agrega un alcance de atributo interno al alcance de A y de puntos a VO. Cuando se define cada función, se creará un atributo de alcance asociado con ella, y el alcance siempre apunta al entorno en el que se define la función. La estructura ECSTACK en este momento es la siguiente:
Ecstack = [// ESCUPTURO STACK EC (G) = {// ENTOBIOLO DE EJECUCIÓN GLOBAL VO (G): {// Definir objeto variable global ... // Contiene los atributos originales del objeto global x = 1; // Definir la variable x a = function () {...}; // Definir la función aa [[alcance]] = this; // Definir el alcance de A y asignar valor a Vo mismo}}];2. Ejecutar la función A
Cuando la ejecución ingresa a (1), el motor JS debe hacer lo siguiente:
Primero, el motor JS creará el entorno de ejecución EC de la función A, y luego la CE lo empujará a la parte superior de la pila de entorno de ejecución y obtendrá los derechos de ejecución. En este momento, hay dos entornos de ejecución en la pila de entorno de ejecución, a saber, el entorno de ejecución global y la función de un entorno de ejecución. El entorno de ejecución de A está en la parte superior de la pila, y el entorno de ejecución global está en la parte inferior de la pila. Luego, cree la cadena de alcance de la función A. En JavaScript, cada entorno de ejecución tiene su propia cadena de alcance para la resolución del identificador. Cuando se crea el entorno de ejecución, su cadena de alcance se inicializa como el objeto contenido en el alcance de la función de ejecución actualmente.
A continuación, el motor JS creará un objeto activo (objeto de activación) AO de la función actual. El objeto activo aquí juega el papel de un objeto variable, pero se llama de manera diferente en la función (puede pensar que un objeto variable es un concepto general, y el objeto activo es una rama de él). AO contiene los parámetros formales de la función, el objeto de argumentos, este objeto, así como las definiciones de variables locales y funciones internas, y luego AO se empujará a la parte superior de la cadena de alcance. Cabe señalar que al definir la función B, el motor JS también agregará un atributo de alcance a B y un alcance de puntos al entorno donde se define la función B. El entorno donde se define la función B es el objeto activo AO de A, y AO se encuentra en la parte delantera de la lista vinculada. Dado que la lista vinculada tiene las características de la conexión final, el alcance de la función B apunta a toda la cadena de alcance de A. Echemos un vistazo a la estructura Ecstack en este momento:
Ecstack = [// ESCEUCIÓN STACK EC (A) = {// ASECCIÓN DE EJECUCIÓN DE EJECUCIÓN [ACUCHA]: VO (G), // VO es el objeto variable global Ao (a): {// Cree el objeto activo y: 1, x: 2, // Definir la variable local x B: function () {...}, // definir la función BB [[SCOPE]] = esto; // Esto se refiere a AO en sí mismo, y AO está en la parte superior de Scopechain, por lo que B [[ACCEN]] señala a los argumentos de la cadena de alcance completo: [], // Los argumentos que accedemos en la función son argumentos en esta: Window // this en la función apunta al objeto de ventana de llamadas}, ScopeChain: <ao (a), a [[ámbito]]>//la lista de la lista es inicialmente la lista. Luego se agrega AO a la parte superior de la cadena de alcance. En este momento, la cadena de alcance de A: ao (a)-> vo (g)}, ec (g) = {// entorno de ejecución global vo (g): {// Crear objeto variable global ... // Contiene los atributos originales del objeto global x = 1; // Defina la variable x a = function () {...}; // Defina la función aa [[alcance]] = this; // Defina el alcance de A, a [[ELCOPE]] == VO (G)}}];3. Ejecutar la función B
Después de que la función A se ejecuta, la referencia a B se devuelve y se asigna a la variable C. La ejecución de C (1) es equivalente a la ejecución B (1). El motor JS necesita completar las siguientes tareas:
Primero, como arriba, cree el entorno de ejecución EC de la función B, y luego empuje la CE a la parte superior de la pila de entorno de ejecución y obtenga los derechos de ejecución. En este momento, hay dos entornos de ejecución en la pila de entorno de ejecución, a saber, el entorno de ejecución global y el entorno de ejecución de la función B. El entorno de ejecución de B está en la parte superior de la pila, y el entorno de ejecución global está en la parte inferior de la pila. (Nota: Cuando la función A retorna, el entorno de ejecución de A se eliminará de la pila, dejando solo el entorno de ejecución global) Luego, cree la cadena de alcance de la función B e inicializará en el objeto contenido en el alcance de la función B, es decir, la cadena de alcance de A. Finalmente, cree el objeto activo de la función B y use los parámetros z Z, argumentos objeto y este objeto de B As Propiedades de AO. En este momento, Ecstack se volverá así:
Ecstack = [// ESCEUCIÓN STACK EC (B) = {// Crear entorno de ejecución de B y está en la parte superior de la cadena de alcance [alcance]: ao (a), // apunte a la cadena de alcance de la función A, ao (a)-> vo (g) var ao (b) = {// Crea el objeto activo de la función b z: 1, argumentos: [], esta: ventana}} ScopeChain: <ao (b), b [[alcance]]> // La lista vinculada se inicializa a B [[Alcance]], y luego Ao (b) se agrega al encabezado de la lista vinculada. En este momento, la cadena de alcance de B: Ao (b)-> ao (a) -vo (g)}, ec (a), // El entorno de ejecución de A se ha eliminado de la parte superior de la pila, ec (g) = {// entorno de ejecución global vo: {// Definir objeto variable global ... // Contiene los atributos originales del objeto global x = 1; // Definir la variable x a = function () {...}; // Definir la función aa [[alcance]] = this; // Definir el alcance de a, a [[alcance]] == vo (g)}}];Cuando la función B ejecuta "x+y+z", es necesario analizar los tres identificadores x, y y z uno por uno. El proceso de análisis se adhiere a las reglas de búsqueda de variables: primero encuentre si el atributo existe en su objeto activo. Si existe, deje de buscar y regrese; Si no existe, continúe buscando desde la parte superior a lo largo de su cadena de alcance, hasta que se encuentre. Si la variable no se encuentra en toda la cadena de alcance, regrese "indefinido". Del análisis anterior, podemos ver que la cadena de alcance de la función B es la siguiente:
Ao (b)-> ao (a)-> vo (g)
Por lo tanto, la variable X se encontrará en AO (a), y no buscará x en Vo (g), la variable y se encontrará en AO (a), y la variable z se encontrará en su propia AO (b). Entonces el resultado de la ejecución: 2+1+1 = 4.
Resumen simple
Después de comprender el mecanismo de trabajo del motor JS, no podemos permanecer en el nivel de comprensión del concepto, pero usarlo como una herramienta básica para optimizar y mejorar nuestro código en el trabajo real, mejorar la eficiencia de la ejecución y generar un valor real. Tome el mecanismo de búsqueda de variables como ejemplo. Si su código está profundamente anidado y cada vez que se refiere a una variable global, el motor JS buscará toda la cadena de alcance. Por ejemplo, existe este problema con los objetos de ventana y documento en la parte inferior de la cadena de alcance. Por lo tanto, podemos hacer un gran trabajo de optimización del rendimiento en torno a este problema y, por supuesto, hay otros aspectos de las optimizaciones. No voy a entrar en detalles aquí. ¡Este artículo se considera un aviso!
por @一竞 2015
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.