Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

215
Vistas
Explicación de `let` y alcance de bloque con bucles for

Entiendo que let evita declaraciones duplicadas, lo cual es bueno.

 let x; let x; // error!

Las variables declaradas con let también se pueden usar en cierres que se pueden esperar

 let i = 100; setTimeout(function () { console.log(i) }, i); // '100' after 100 ms

Lo que me cuesta un poco entender es cómo let se aplica a los bucles. Esto parece ser específico for bucles. Considere el problema clásico:

 // prints '10' 10 times for (var i = 0; i < 10; i++) { process.nextTick(_ => console.log(i)) } // prints '0' through '9' for (let i = 0; i < 10; i++) { process.nextTick(_ => console.log(i)) }

¿Por qué funciona el uso de let en este contexto? En mi imaginación, aunque solo se ve un bloque, for realidad crea un bloque separado para cada iteración y la declaración let se realiza dentro de ese bloque ... pero solo hay una declaración let para inicializar el valor. ¿Es esto solo azúcar sintáctico para ES6? ¿Cómo funciona esto?

Entiendo las diferencias entre var y let y las he ilustrado arriba. Estoy particularmente interesado en entender por qué las diferentes declaraciones dan como resultado una salida diferente usando un bucle for .

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

¿Es esto solo azúcar sintáctico para ES6?

No, es más que azúcar sintáctico. Los detalles sangrientos están enterrados en §13.6.3.9 CreatePerIterationEnvironment .

¿Cómo funciona esto?

Si usa esa palabra clave let en la declaración for , verificará qué nombres vincula y luego

  • cree un nuevo entorno léxico con esos nombres para a) la expresión inicializadora b) cada iteración (antes de evaluar la expresión de incremento)
  • copie los valores de todas las variables con esos nombres de uno a otro entorno

Su instrucción de bucle for (var i = 0; i < 10; i++) process.nextTick(_ => console.log(i)); desazúcares a un simple

 // omitting braces when they don't introduce a block var i; i = 0; if (i < 10) process.nextTick(_ => console.log(i)) i++; if (i < 10) process.nextTick(_ => console.log(i)) i++; …

while for (let i = 0; i < 10; i++) process.nextTick(_ => console.log(i)); hace "desugar" a lo mucho mas complicado

 // using braces to explicitly denote block scopes, // using indentation for control flow { let i; i = 0; __status = {i}; } { let {i} = __status; if (i < 10) process.nextTick(_ => console.log(i)) __status = {i}; } { let {i} = __status; i++; if (i < 10) process.nextTick(_ => console.log(i)) __status = {i}; } { let {i} = __status; i++; …
over 4 years ago · Santiago Trujillo Denunciar

0

Encontré esta explicación del libro Exploring ES6 la mejor:

var-declarar una variable en el encabezado de un bucle for crea un enlace único (espacio de almacenamiento) para esa variable:

 const arr = []; for (var i=0; i < 3; i++) { arr.push(() => i); } arr.map(x => x()); // [3,3,3]

Cada i en los cuerpos de las tres funciones de flecha se refiere al mismo enlace, por lo que todas devuelven el mismo valor.

Si declara una variable, se crea un nuevo enlace para cada iteración del bucle:

 const arr = []; for (let i=0; i < 3; i++) { arr.push(() => i); } arr.map(x => x()); // [0,1,2]

Esta vez, cada i se refiere al enlace de una iteración específica y conserva el valor actual en ese momento. Por lo tanto, cada función de flecha devuelve un valor diferente.

over 4 years ago · Santiago Trujillo Denunciar

0

let introduce el alcance del bloque y el enlace equivalente, al igual que las funciones crean un alcance con el cierre. Creo que la sección relevante de la especificación es 13.2.1 , donde la nota menciona que las declaraciones let son parte de un LexicalBinding y ambas viven dentro de un Lexical Environment. La sección 13.2.2 establece que las declaraciones de var se adjuntan a un entorno variable, en lugar de a un enlace léxico.

La explicación de MDN también respalda esto, afirmando que:

Funciona vinculando cero o más variables en el ámbito léxico de un solo bloque de código.

lo que sugiere que las variables están vinculadas al bloque, que varía cada iteración y requiere un nuevo LexicalBinding (creo que no al 100% en ese punto), en lugar del Lexical Environment o VariableEnvironment circundante, que sería constante durante la duración de la llamada.

En resumen, cuando se usa let , el cierre está en el cuerpo del bucle y la variable es diferente cada vez, por lo que debe capturarse nuevamente. Cuando se usa var , la variable está en la función circundante, por lo que no es necesario volver a cerrar y se pasa la misma referencia a cada iteración.

Adaptando su ejemplo para ejecutar en el navegador:

 // prints '10' 10 times for (var i = 0; i < 10; i++) { setTimeout(_ => console.log('var', i), 0); } // prints '0' through '9' for (let i = 0; i < 10; i++) { setTimeout(_ => console.log('let', i), 0); }

ciertamente muestra este último imprimiendo cada valor. Si observa cómo Babel transpila esto, produce:

 for (var i = 0; i < 10; i++) { setTimeout(function(_) { return console.log(i); }, 0); } var _loop = function(_i) { setTimeout(function(_) { return console.log(_i); }, 0); }; // prints '0' through '9' for (var _i = 0; _i < 10; _i++) { _loop(_i); }

Asumiendo que Babel es bastante conforme, eso coincide con mi interpretación de la especificación.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda