Aumento de alcance

Alcance

  • En primer lugar, el alcance es un conjunto de reglas para determinar dónde y cómo encontrar variables (identificadores). Si el propósito de la búsqueda es asignar un valor a una variable, se utilizará la consulta LHS. Si el propósito es obtener el valor de la variable, se utilizará la consulta RHS. El operador de asignación genera consultas LHS. = Los operadores u operaciones que pasan parámetros al llamar a una función provocarán una operación de copia en el ámbito asociado.

Principio de compilación

  1. JS es un lenguaje compilado. En el proceso tradicional de compilación de lenguajes, una parte del código fuente de un programa pasará por tres pasos antes de ejecutarse, lo que se denomina colectivamente "compilación".
    • Segmentación de palabras / análisis léxico. Este proceso divide una cadena de caracteres en (para un lenguaje de programación) bloques de código significativos, que se denominan tokens. Por ejemplo: var a = 2; se dividirá en var, a, =, 2,;.
    • Análisis de análisis / gramática. Este proceso consiste en transformar la secuencia (matriz) de unidades léxicas en un árbol compuesto de elementos anidados uno por uno y que representan la estructura de sintaxis del programa. Este árbol se denomina "árbol de sintaxis abstracta".
    • Generación de código. El proceso de convertir AST en código ejecutable se llama generación de código.

Comprender el alcance

  1. El motor puede crear y almacenar variables según sea necesario, y es responsable de la compilación y ejecución de todo el programa JavaScript de principio a fin.
  2. Compilador, responsable del análisis gramatical y la generación de código y otros trabajos sucios (principio de compilación)
  3. El alcance es responsable de recopilar y mantener una serie de consultas compuestas de todos los identificadores declarados (variables), e implementar un conjunto muy estricto de reglas para determinar los derechos de acceso del código ejecutado actualmente a estos identificadores.
  4. La operación de asignación de variables realizará dos acciones: primero, el compilador declarará una variable en el alcance actual (si no se ha declarado antes), y luego el motor de tiempo de ejecución buscará la variable en el alcance. Es asignado

Compilador

  1. El compilador generó código en el segundo paso del proceso de compilación. Cuando el motor lo ejecute, utilizará la variable de búsqueda a para determinar si se ha declarado. El proceso de búsqueda está coordinado por el alcance, pero el motor realiza dicha búsqueda, lo que afectará el resultado final de la búsqueda.
  2. El motor consultará la variable a para LHS. Otro tipo de búsqueda RHS.
  3. La búsqueda de LHS es tratar de encontrar el contenedor de la variable en sí, de modo que se le pueda asignar, lo que se entiende como "quién es el objetivo de la operación de asignación". Consulta RHS y búsqueda simple, el valor de una variable es el mismo, entendido como "quién es la fuente de la operación de asignación".
  4. El motor de JavaScript primero compilará el código antes de que se ejecute. Durante este proceso, una declaración como var a = 2 se dividirá en dos pasos separados:
    • Primero, var a declara nuevas variables en su alcance. Esta vez al principio, antes de que se ejecute el código.
    • A continuación, a = 2 consultará (consulta LHS) la variable a y le asignará un valor.
  5. El compilador puede procesar declaraciones y definiciones valiosas al mismo tiempo que se genera el código.

Alcance de anidamiento

  1. Cuando una función rápida o está anidada en otro bloque o función, se produce la anidación del alcance.
  2. Reglas para atravesar cadenas de alcance anidadas: el motor comienza a buscar variables del alcance de ejecución actual y, si no puede encontrarlo, continúa buscando un nivel. Al alcanzar el alcance global más externo, el proceso de búsqueda se detendrá si se encuentra o no.

Anormal

  1. Si la consulta RHS no puede encontrar la variable requerida en todos los ámbitos anidados, el motor generará una excepción ReferenceErrer.
  2. Cuando el motor ejecuta la consulta LHS, si la variable de destino no se puede encontrar en el nivel superior (ámbito global), se creará una variable con este nombre en el ámbito global y se devolverá al motor, siempre que el programa se ejecute en un " Modo estricto ". En "modo estricto" el motor lanzará una excepción ReferenceErrer.
  3. Si la consulta RHS encuentra una variable, pero intenta realizar operaciones no razonables sobre el valor de la variable, como intentar realizar una llamada a la función en un valor del tipo de función de tarifa, o hacer referencia al atributo en el valor del tipo nulo o indefinido, qué motor Se lanzará TypeError.
  4. ReferenceErrer está relacionado con el fracaso de la discriminación del alcance, mientras que TypeError significa que la discriminación del alcance es exitosa, pero la operación del resultado es ilegal o irrazonable.

Alcance léxico

"Alcance" se define como un conjunto de reglas utilizadas para administrar cómo el motor busca variables basadas en el nombre del identificador en el alcance actual y los sub-ámbitos anidados.

Etapa léxica

  1. La primera etapa de trabajo de la mayoría de los compiladores de lenguaje estándar se llama palabras léxicas (también llamada lexicalización). El proceso de lexicalización verificará los caracteres en el código fuente, y si es un proceso de análisis con estado, también le dará a la palabra semántica.
  2. El alcance léxico es el alcance definido en la etapa léxica. El alcance léxico está determinado por el lugar donde escribe variables y bloquea el alcance cuando escribe código, por lo que cuando el analizador léxico procesa el código, mantendrá el alcance sin cambios (en la mayoría de los casos).

Encontrar

  1. La búsqueda de alcance se detendrá cuando se encuentre el primer identificador coincidente. Los identificadores con el mismo nombre se pueden definir en varias capas de ámbitos anidados, lo que se denomina "efecto de sombreado". Además del efecto de sombreado, los sustos de alcance siempre comienzan desde el alcance más interno en el que se está ejecutando, paso a paso hacia afuera o hacia arriba, hasta que encuentra directamente el primer identificador coincidente.
  2. No importa dónde se llame la función, y no importa cómo se llame, su alcance léxico solo está determinado por la posición donde se declara la función.

Léxico engañoso

  1. Hay dos mecanismos en JavaScript para lograr el propósito de "modificar" (o engañar) el alcance léxico en tiempo de ejecución. Sin embargo, engañar el alcance léxico causará una degradación del rendimiento, y el motor no puede utilizarse para optimizar la búsqueda en el momento de la compilación, porque el motor solo puede considerar cuidadosamente que dicha optimización no es válida.

  2. La función eval (...) en javascript puede aceptar una caja de cadenas como parámetros, y el contenido es código que parece existir en esta posición en el programa en el momento de la escritura. Al ejecutar el código después de eval (...), el motor no "sabe" o "cuida" que el código anterior se inserte de forma dinámica y que el entorno del ámbito léxico se modifique. El motor solo realizará búsquedas de alcance léxico como de costumbre.

    function foo(str,a){
        eval(str);//欺骗console.log(a,b);
     }
    val b = 2; 
    foo("var b = 3;",1);//1,3
    
  3. eval (...) se usa generalmente para ejecutar código creado dinámicamente.

con

  1. usualmente se usa como un atajo para referirse repetidamente a múltiples atributos en el mismo objeto, sin tener que referirse repetidamente al objeto.
  2. with puede decir que un objeto sin atributos o con múltiples atributos se trata como un ámbito léxico completamente aislado, por lo que los atributos de este objeto también se tratan como identificadores léxicos definidos en este ámbito.
  3. Si la función eval (...) acepta código que contiene una o más declaraciones, modificará el alcance léxico en el que se encuentra, y la instrucción with realmente crea un nuevo alcance léxico basado en el objeto que le pasa .
  4. eval (...) y with se verán afectados (restringidos) por el modo estricto. está completamente prohibido, y bajo la premisa de retener funciones básicas, también está prohibida la introducción o el uso inseguro de eval (...).

Alcance funcional y alcance rápido

Alcance de la función

El significado del alcance de la función significa que todos los haces de conexión que pertenecen a esta función se pueden usar y reutilizar dentro del alcance de la función completa (de hecho, también se puede usar en un alcance anidado). Este diseño es muy útil, puede hacer uso completo de las variables de JavaScript y puede cambiar las características "dinámicas" del tipo de valor según sea necesario.

Ocultar implementación interna

  1. Elegir un fragmento de código arbitrario y luego envolverlo con una declaración de función en realidad oculta el código.
  2. El resultado real es que se crea una burbuja de alcance alrededor de este fragmento de código, lo que significa que cualquier declaración (variable, función) de leche de soja en este código está vinculada al alcance de esta nueva función de empaque innovadora, no a la anterior En el alcance. En otras palabras, podemos envolver variables y funciones en el alcance de una función, y luego usar este alcance para "ocultarlas".
  3. La mayoría de las variables y funciones "ocultas" se aplican desde el principio de menor privilegio, que también se denomina principio de mínima autorización o menor exposición.

Evitar conflictos

Otro beneficio de las variables y funciones en el ámbito "oculto" es evitar conflictos entre identificadores del mismo nombre. Dos identificadores pueden tener el mismo nombre pero tener usos diferentes, y pueden causar conflictos de nombres involuntariamente . Los conflictos pueden causar que los valores de las variables se sobrescriban accidentalmente.

Alcance de la función

  1. La forma más fácil de distinguir entre declaraciones y expresiones de funciones es ver dónde aparece la palabra clave de función en la declaración (no solo una línea de código, sino la posición en toda la declaración). Si función es la primera palabra en la declaración, entonces es una declaración de función, de lo contrario es una expresión de función.
  2. La diferencia más importante entre las declaraciones de función y las expresiones de función es dónde se vincularán sus identificadores de nombre. (function foo () {...}) La expresión de función significa que solo se puede acceder a foo en la posición representada por ..., no en el ámbito externo. El nombre de la variable foo está oculto en sí mismo, pensando que no contaminará innecesariamente el alcance externo.

Anónimo y nombrado

setTimeout(function(){
        console.log('I waited');
 },100);
  1. Esto se llama una expresión de función anónima porque function () ... no tiene un identificador de nombre.
  2. Desventajas de las funciones anónimas:
    • Las funciones anónimas no muestran nombres de funciones significativos en el seguimiento de la pila, lo que dificulta la depuración.
    • Si no hay un nombre de función, solo se puede usar la referencia de argumentos.calles expirada cuando la función necesita referirse a sí misma.
    • Las funciones anónimas omiten nombres de funciones que son importantes para la legibilidad / comprensión del código. Un nombre descriptivo puede hacer que el código se explique por sí mismo.
  3. Siempre nombre las expresiones de función: agregue un nombre después de function ()

Ejecute la expresión de la función de inmediato

  1. Dado que la función está encerrada entre un par de paréntesis (), se convierte en una expresión. Puede ejecutar la función inmediatamente agregando otro () al final, como (function foo () {...}) (). La primera función se convierte en una expresión, y la segunda () ejecuta esta función.

  2. IIFE: significa ejecución inmediata de expresiones de función.

  3. En comparación con el IIFE tradicional, hay otra forma mejorada: (function () {…} ()). Estas dos funciones formales son consistentes.

  4. Otro uso avanzado muy común de IIFE es tratarlos como llamadas a funciones y pasar parámetros.

     var a = 2;
     (function IIFE(global){
         var a = 3;
         console.log(a);//3
         console.log(global.a);//2
     })(window);
     console.log(a);
    

Otro escenario de aplicación para este patrón es resolver las excepciones causadas por el valor predeterminado del identificador indefinido que se sobrescribe por errores (aunque no es común). Hable de un parámetro llamado indefinido, pero no se pasa ningún valor en la posición correspondiente, para garantizar que el valor del identificador indefinido en el bloque de código sea realmente indefinido.
5. Otro uso de IIFE es invertir el orden de ejecución del código, colocar las funciones requeridas en segundo lugar y pasarlas como parámetros después de ejecutar el IIFE.

Alcance del bloque

  1. ancho también es un ejemplo de ámbito de bloque (una forma de ámbito de bloque). Los ámbitos creados a partir de objetos con con solo son válidos en la instrucción with y no en el ámbito externo.

  2. La especificación ES3 de javascript estipula que la cláusula try / catch creará un alcance de bloque, en el que las variables declaradas solo son válidas dentro del catch.

     try{
         undifined();//执行一个非法操作来强制制造一个异常
     }
     catch(err){
         console.log(err);//能够正常执行!
     }
     console.log(err);//ReferenceError
    
  3. Para evitar advertencias innecesarias de errores de unión de inspección estática cuando dos o más cláusulas catch en el mismo alcance usan el mismo nombre de identificador, muchos desarrolladores nombrarán los parámetros catch como err1, err2, etc. . Algunos desarrolladores simplemente cierran la herramienta de verificación estática para buscar nombres de variables duplicados.

dejar

  1. La palabra clave let puede vincular variables a cualquier ámbito (generalmente {…} dentro). En otras palabras, let secuestra implícitamente el alcance del bloque en el que la variable declarada por let.

  2. El acto de adjuntar variables a un ámbito de bloque existente con let es implícito. El código mostrado se debe a un código implícito o algo delicado pero poco claro. El siguiente es el código de visualización:

     var foo = true;
     if(foo){
         {//显示代码块
             let bar = foo * 2;bar = something(bar);
             console.log(bar);
         }
     }
    
  3. Mientras la declaración sea válida, puede usar {...} corchetes en cualquier parte de la declaración para crear un bloque que permita vincular. En este ejemplo, se crea explícitamente un bloque dentro de la instrucción if. Si necesita ser refactorizado, todo el bloque se puede mover fácilmente sin afectar la posición y la semántica de la instrucción if externa.

const

ES6 también introdujo const, que también se puede usar para crear variables de alcance de bloque, pero su valor es fijo (constante). Cualquier intento posterior de modificar la operación que vale la pena causará un error.

Promover

El compilador ataca de nuevo

  1. Parte del trabajo en la fase de compilación es encontrar todas las declaraciones y asociarlas con el alcance apropiado.
    a = 2; var a; console.log (a); // generará 2
  2. var a = 2; en realidad se verá como var a; y a = 2; la primera declaración de definición se realiza durante la fase de compilación. La segunda declaración de asignación se dejará en su lugar para su ejecución. Es decir, declare primero y luego asigne valores.
  3. Esto significa que siempre que aparezca la declaración en el ámbito, se procesará antes de que se ejecute el código. Este proceso se puede imaginar visualmente ya que todas las declaraciones (variables y funciones) se "moverán" a la parte superior de sus respectivos ámbitos. Este proceso se llama promoción.
    4. Tenga en cuenta que se promocionará cada alcance.
    5. La declaración en sí será promovida, y las operaciones de asignación que incluyen la asignación de expresiones de función no serán promovidas.

Función primero

1. Se promoverán las declaraciones de funciones y variables. Sin embargo, debe tenerse en cuenta que hay un detalle (este detalle puede aparecer en el código con múltiples declaraciones "duplicadas") de que la función se promocionará primero y luego la variable.

    foo();//1 var foo; 
    function foo(){
        console.log(1);
    }
    foo = function(){
        console.log(2);
    };//会输出1而不是2
  1. Aunque se ignorarán las declaraciones var repetidas, las declaraciones de funciones que aparecen en la parte posterior cubren las declaraciones de funciones anteriores.

La definición y ejemplos de este artículo están tomados de:

  • "JavaScript que no sabías"
17 artículos originales publicados · elogiados 0 · visitas 771

Supongo que te gusta

Origin blog.csdn.net/CandiceYu/article/details/89136613
Recomendado
Clasificación