Platzi
Platzi

¡Invierte en ti y celebremos! Adquiere un plan Expert o Expert+ a precio especial.

Antes: $349
$259
Currency
Antes: $349
Ahorras: $90
COMIENZA AHORA
Termina en: 13D : 7H : 44M : 50S

No tienes acceso a esta clase

Para ver esta clase necesitas una suscripción a Platzi

Block Scope5/12

Tuve curiosidad de por que al instructor cuando ejecutaba la función llamada anotherFunction con un for inicializado con la palabra reservada var se mostraba el numero diez en consola, entonces decidí investigar un poco; la respuesta tiene que ver con el Hoisting y Asincronía o EventLoop.
.
Esto es algo como lo que tiene el instructor:

function functionName() {
	// Para este ejemplo declarare que el for solo de 3 "vueltas", es decir la condición sera: i < 3.
	for(var i = 0; i < 3; i++) {
		setTimeout(function() {
			console.log(i);
		}, 1000);
	}
	
	console.log('El valor final de "i" es: ' + i);
}

El hoisting hace que la variable con el nombre i dentro del for se “eleve” y sea asignada en memoria, por lo tanto a lo último se estará reasignando el ultimo incremento que tuvo y se podrá acceder a ella en cualquier punto dentro de la función functionName.

function functionName() {
	var i;
	for(i = 0; i < 3; i++) {
		setTimeout(function() {
			console.log(i);
		}, 1000);
	}
	// Este console.log podra acceder a i aun afuera del for, esto por que la variable i fue declarada y asignada antes que todo en tiempo de ejecución (hoisting).
	console.log('El valor final de "i" es: ' + i);
}

Entonces asumiendo eso y respondiendo a la pregunta de por que el console.log que esta adentro del setTimout solo imprime el valor final de i llegue a la siguiente conclusión:
.

  1. El for estará ejecutándose en el Call Stack mientras la condición propuesta en el for (i < 3) se cumpla, por tanto también se ejecutara el setTimeout cada que la condición del for sea verdadera, sin embargo hay que recordar que el setTimeout es una función del navegador, entonces el setTimeout pasara a ejecutarse en “segundo plano” y una vez que los tiempos de espera definidos de los setTimeout se cumplan, estos pasaran al Callback Queue.
    .
  2. Una vez que la condición del for ya no se cumpla, pasara a ejecutar el console.log que mostrará el valor final que para entonces será igual a 3 por que el for ya estuvo mutando el valor con cada incremento (i++).
    .
  3. Posteriormente ya cuando el Call Stack esta vació pasaran a ejecutarse el callback de cada setTimeout que a su vez ejecutan un console.log imprimiendo el valor de la variable i, recordando que i ya tiene el valor final de 3 por que se había incrementado en uno en cada “vuelta” que daba el for.
    .
    Capture.JPG
    .
    Referencias:
    JavaScript closure inside loops – simple practical example

    Is it best to use “var” or “let” in for loop iterations or does it even matter?
    .

Un videíto increíble de var, let y const por si gustan entender mejor el scope

.
var.png
https://www.youtube.com/watch?v=ojrvxYcKeYg

Con var , tiene un scope de función y solo un enlace compartido para todas sus iteraciones de bucle, es decir, i en cada callback setTimeout significa la misma variable que finalmente es igual a 6 después de que finaliza la iteración del bucle.

Con let tener un scope de bloque y cuando se utiliza en el ciclo for obtiene un enlace nuevo para cada iteración, es decir, el i en cada callback setTimeout significa una variable diferente, cada una de las cuales tiene un valor diferente: la primera es 0, la el siguiente es 1 etc.

Ahora, ¿Pero por qué me devuelve 10 veces 10? ¿No debería devolverme 10 veces 9?
veamos la declaración del ciclo for:

for (var i = 0; i < 10; i++) {
	...
}

El ciclo for termina cuando la condición (i < 10) sea falsa, osea que mientras sea verdadera el recorrerá el ciclo. La variable i aumentará su valor en 1 (i++) por cada iteración, osea que tomará estos valores: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10). Toma el 10 porque es ese el valor donde la condición (i < 10) es falsa puesto que 10 no es menor que 10, si no que es igual… y el ciclo termina.
Espero haberles ayudado y que hayan aclarado sus dudas!

Si todavía se les complica entender, les dejo el enlace de la explicación del profesor Richard!!

Les dejo esta infografia como breve resumen de lo que es el Scope. espero sea util 😃
scope1.jpg

El block scope gue algo que me rompió cuando lo aprendí, porque si no me equivoco, no hay más lenguajes que lo tengan jaja (o igual si) pero aún no los conozco

Para explicar un poco mejor qué fue lo que sucedió con el timeOut, al declarar con “var” la variable “i” dentro del for, lo que estamos haciendo es declarar una variable global llamada “i”, y con cada iteración del for estamos sobreescribiendo esa variable, el for del 1 al 10 se ejecuta en menos de un segundo, es decir, una computadora es rápida ejecutando código, pero el setTimeout se ejecutará después de un segundo, JavaScript NO se va a quedar esperando que cada setTimeout se ejecute, simplemente JavaScript va a ver que hay un setTimeout y lo va a poner en su cola de tareas (Ver el curso de asíncronismo con JavaScript y el curso profesional de JavaScript para entender esto mejor), el caso es que, cuando pasa un segundo, los 10 setTimeouts que JavaScript puso en cola (Uno por cada iteración) se ejecutan, y como “i” es una variable global que fue sobreescrita, se quedo con el último valor de 10 (Porque aunque la condición del último ciclo no se cumplió, la variable si fue asignada para poder evaluar la condición), y es por eso que todos los setTimeouts miran el valor de la variable y todos acaban obteniendo “10”, con let, como saben, no se puede sobreescribir la variable, y tenemos un “let” diferente por cada iteración (Imaginen que cada iteración es un bloque de código totalmente diferente), entonces, cada setTimeout agarra el “let” que está dentro de su propio bloque de código, y como es único gracias al scope, ahí si que se imprimen del 1 al 9:D!

En for no debemos utilizar var i = 0 porque al imprimir va imprimir 10 veces el ultimo valor, ejemplo:

//for no debemos utilizar var sino let
const anotherFunction = () => {
  for (var i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i)
    }, 1000)
  }
}
anotherFunction()

Va imprimir: 10 10 10 10 10 10 10 10 10 10
**Pero con let: **

const anotherFunction = () => {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i)
    }, 1000)
  }
}
anotherFunction()

Va imprimir: 0 1 2 3 4 5 6 7 8 9

Dentro de una función podemos tener un bloque de código, por ejemplo: un if, mientras lo llamamos sobre una llave estará guardado dentro de un bloque.

Si definimos un elemento con var podemos acceder en todos los elementos de la función, si lo llamamos fuera del bloque donde está, vamos a poder acceder a ese elemento.

Con let y const no vamos a poder acceder a ellos porque se establecen dentro del bloque, solo se puede acceder a ellos dentro de ese bloque.

muy importante y ultil el uso de let.

const fruit = () => {
    if (true) {
        //De esta forma puedo acceder a las variables declaradas dentro del IF, se puede acceder a ellas fuera del IF
        // var fruit1 = 'Apple';
        // var fruit2 = 'Banana';
        // var fruit3 = 'Kiwi';
        //cuando declaro las variables con LET y/o CONST dentro del IF, son locales para el bloque de codigo del IF
        //y no las puede acceder fuera del bloque IF, asi esten en la misma funcion
        var fruit1 = 'Apple';
        let fruit2 = 'Banana';
        const fruit3 = 'Kiwi';

        console.log(fruit2);
        console.log(fruit3);
    }

    console.log(fruit1);
    // console.log(fruit2);
    // console.log(fruit3);

    //para poder acceder a las variables fruit2 y fruit3, debo colocarlas dentro del bloque de codigo donde fueron declaradas , en este caso IF
}

fruit();

// //Esta variable esta en ambito globa,
// let x = 1;
// {
//     //esta variable esta en ambito local, 
//     //y asi tenga el mismo nombre de la del ambito local, mantienen cada una su valor
//     let x = 2;
//     console.log(x);
// }
// console.log(x);

var x = 1;
{
    //esta variable esta en ambito local, 
    //y asi tenga el mismo nombre de la del ambito local, 
    //la asignacion hecha del ambito local se transfiere a la variable global
    var x = 2;
    console.log(x);
}
console.log(x);


// De esta forma solo muestra el valor diez, aunque lo muestra 10 veces, 
//esto ocurre porque nos muestra el ultimo valor de la variable
// dentro del ambito del ciclo for esta asignado el diez.
// const anotherFunction = () => {
//     for (var i = 0; i < 10; i++) {
//         setTimeout(() => {
//             console.log (i);
//         }, 1000)
//     }
// };

//al cambiar la forma de asignacion de declaraciòn de la variaable dentro del FOR,
//y usar LET, no muestra el resultado esperado.
const anotherFunction = () => {
    for (let i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log (i);
        }, 1000)
    }
};

anotherFunction();

https://platzi.com/clases/1807-scope/25874-block-scope/?time=417 Esta fue una pregunta de entrevista de screening, define la salida de una ciclo usando var y let dentro de un setTimeout ¿cual es la salida? 😉

Oscar lo explica perfecto pero por si gustan otro ejemplo adicional recomiendo este video: https://youtu.be/kQwaq2MMZ-Y

Siempre let nunca inlet😁

me exploto la cabeza con el ejemplo del for 😮

Ok!! no sabía eso de quel scope del var aplica dentro de una función y que el scope del let y const aplica dentro de un bloque, mind blowing!

por lo que entendí, las variables declaradas con var no toman en cuenta el scope de un bloque y se lo “saltan” por así decirlo y lo que hacen es asignar su scope a la función mas cercana o si no existe una función lo hace de manera global.

var es un rebelde sin causa, le sabe a cake las delimitaciones por bloque! 😂

Entonces podríamos ahorrarnos todo esto simplemente usando let y const :3

Un pequeño repaso de los cursos de básico y fundamentos de javascript

A mi me sirvio entenderlo asi
recordemos que al declarar una variable con var esta puede reevaluarse con otro valor y que cuando declaramos una variable lo que estamos haciendo es decirle a la computadora “guardeme este valor en memoria” , entonces cuando paso al console.log(i) lo que hizo fue enviar esta orden a una “lista de tareas” que se ejecutara cuando ya termine de leer todo el codigo.
Entonces cada que realizaba un ciclo, este le decia " mandeme esta funcion a la lista de tareas y la ejecuta ahorita" entonces teniamos 10 veces console.log(i) en espera, cuando termino de ejecutarse todo el codigo, este le dijo a memoria “Cuanto es el valor de i?” y como se declaro con var, fue como si se estuviera reescribiendo en cada ciclo, entonces en memoria lo unico que tenia era que i = 10, por eso imprimio 10 veces el mismo valor.
Ahora ¿Qué pasa con let?¿Por qué si funciona con esto?
Realiza exactamente lo mismo ciclo, pero esta vez en memoria, hay 10 numeros guardados por que let solo permite definir una variable con un valor, no permite reevaluarla, entonces se ejecuto el primer console.log(i) este tomo el primer valor de i que era 1 y luego ocurrio lo mismo con los demas console, pasando uno a uno los valores de i

Espero le sirva a alguien

BLOCK SCOPE APUNTES

//Bloque de codigo es aquel que esta establecido dentro de unas llaves {}

const fruit = () => {

    if(true){

        var fruits = 'apple';
        var fruits2 = 'banana';
        var fruits3 = 'kiwi';

    }

    //vamos a acceder a las variables del if fuera del bloque del if
    console.log(fruits,fruits2,fruits3); // apple banana kiwi

    //---Cuando definimos variables en un bloque distinto con var

    /* Podre acceder a las variables sin problema alguno y podremos accederlos
       Ya que estan establecido dentro del scope de la funcion y esto significa
       El que podamos accederlos en cualquier parte del scope de la funcion */

    // Con let y const

    // No podremos acceder a ellas si estan establecidas con let y const
    // Porque ellas se establecen dentro del bloque en el que estan y solo
    // podran ser accedidas dentro de ese bloque
}

fruit()

let x = 1;

{

    let x = 2;
    console.log(x); //2
}

    console.log(x); //1

//Mismo ejemplo con var 

var x = 1;

{
//Lo que sucede aqui es que el valor reasignado a x tambien cambio en la variable global
// Si queremos declarar un valor debemos hacerlo con let para que este valor
  // trabaje solo en el scope de ese bloque 
    var x = 2;
    console.log(x); //2
}

    console.log(x); //2

const anotherFunction = () => {


    for(let i = 0; i < 10; i++){

        setTimeout(()=>{

            console.log(i);
        }, 1000)


    }
}

anotherFunction(); // al  imprimir la variable i que esta declarada con var
                    // IMPRIME 10 LAS 10 VECES
// Nos muestra este valor ya que esta accediendo al ultimo valor que recorre 
// El for

// La solucion es asignando la variable i con let```

Y lo bueno es que VSC me lo dice de antemano

Screen Shot 2020-12-24 at 10.42.50.png

Por si alguien necesita tener mas claro el temas les dejo este link https://www.youtube.com/watch?v=cTfGyVFrLxQ&t=29s

sigo sin entender el ejemplo del for y el setTimeout.

traté de ejemplificarlo en mi cabeza llevándol al proceso que haría el engine de JS (callstack, callback queue, event loop, etc), pero me sigue sin cuadrar algunas cosas

estuvo muy bien explicado qué es un bloque en JavaScript y su relación con el Scope

excelente clase!

Cuando declaramos una variable tipo var dentro de una función su scope va a poder ser accedido desde cualquier bloque dentro de la función. Let y const por otro lado solo funcionaran dentro del bloque declarado.

supongo que este imprime 10 veces el 10 porque espera al código por el setTimeOut lo que significa que primero ejecuta la función del for, y esta al ser ejecutada pues va a ir sobrescribiendo sus variables, primero var i equivale 0 después 1 después 2 hasta llegar a 10, después de esto ejecuta el setTimeOut del console.log osea el 10 y de nuevo vuelve a hacer este paso vuelve al for sobreescribe las variables y ejecuta el 10 y asi hasta ejecutarlo las 10 veces. pueden hacer la prueba quitando el setTimeOut con el var y notaran que si imprime el ciclo de la manera correcta.

Var === Caos.

Block Scope
A diferencia del scope local este scope está limitado al bloque de código donde fue definida la variable. Desde ECMAScript 6 contamos con los keyword let y const los cuales nos permiten tener un scope de bloque, esto quiere decir que las variables solo van a vivir dentro del bloque de código correspondiente.

Para los que como yo son nuevos en JavaScript y no entendieron muy bien la sintaxis del bucle for del ejemplo del profesor:

The for loop has the following syntax:

for (statement 1; statement 2; statement 3) {

}

Statement 1 is executed (one time) before the execution of the code block.

Statement 2 defines the condition for executing the code block.

Statement 3 is executed (every time) after the code block has been executed.

hace falta un cuadro comparativo de todos los scopes

conclusion tener cuidado al asignar con var

Lo que sucede en realidad es que como javascript es asíncrono entonces hasta que no termine la iteración del For no entraría la función setTimeout

Sabemos que al tener elementos dentro de un bloque de codigo estos podrian funcionar como un scope global, pero si tenemos un BLOQUE dentro de una funcion, esto sera un caso especial, todo depende de la palabra clave que usemos. Si usamos LET o CONST solo funcionaran en el bloque de codigo que seran declarados PERO var si podra ser utilizada y manipulada por LA FUNCION.

let x = 1;
{ 
	let x = 2;
	console.log(x); --> 2
}
console.log(x) --> 1

Scope local en bloques : aplica para las variables declaradas dentro de un bloque(if, for, while, etc.), al declarar una variable con var dentro de un bloque esta si puede ser accedida fuera del bloque porque trabaja dentro del ámbito de la función en cambio al declarar con let y const no se puede porque trabajan únicamente dentro del ámbito bloque.

// Local scope in blocks

const fruits = () => {
  if (true) {
    var fruits1 = "apple";
    // var fruits2 = "banana";
    // var fruits3 = "kiwi";

    let fruits2 = "banana";
    const fruits3 = "kiwi";

    console.log(fruits2);
    console.log(fruits3);
  }

  console.log(fruits1);
  // console.log(fruits2);
  // console.log(fruits3);
};

fruits();

let x = 1;

{
  let x = 2;
  console.log(x);
}
console.log(x);

var x = 1;

{
  var x = 2;
  console.log(x);
}
console.log(x);

const anotherFunction = () => {
  for (var i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i);
    }, 1000);
  }
};

anotherFunction();

const anotherFunction = () => {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i);
    }, 1000);
  }
};

anotherFunction();

Si desean las notas que voy a ir tomando de los cursos las voy a publicar en un repositorio, se las comparto estas son las de este curso:

https://github.com/patogalarzar/code-notes/tree/main/Closures-Scope

Cuando declaramos con let y const el scope de la variable es el bloque (no la función), en este caso sólo existen dentro del if.

Cuando declaramos con let y const el scope de la variable es el bloque (no la función), en este caso sólo existen dentro del if.

lamentablemente sigue llamando ‘asignacion’ a lo que es ‘declaracion’, pero no hay que confundir ese concepto.

Luego de darle al coco un rato, esta fue la manera en que pude organizar las cosas en mi mente:
//

function printNumbers() {
	for (var i = 0; i < 5; i++) {
		setTimeout(
      function printer() {
	      console.log(i);
	    } ,100 * i ); }
}

printNumbers();

//ocurre el primer ciclo

function printNumbers() {
	var i
	for (i = 0; i < 5; i++) {
		i = 0;    //esto se sale para arriba, afuera del for
		setTimeout(
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}
}

/*se ejecuta con 0 pero la condicion del ciclo for la ejecuta el navegador y la pone en 
el callstack, mientras setTimeout pone su funcion de console.log en el callback queue po
ende las ordenes de console.log estan lista para ejecutarse solo despues que lo que esta
en el callstack que es la condicion for con los valore de i*/

//Todo es culpa del hoisting, porque VAR tiene scope de Funcion y let scope de Bloque
//Cuando el codigo itera va a pasar lo siguiente 
//se ejecuta cada bloque for 

var i = 0
/*la variable i que se salio por el hoisting, era undefined, pero luego en el ciclo
for fue asiganada como 0 */
//mientras, por el otro lado, se agenda un console.log en el callback queue
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}
/*como cada vez que el ciclo corre, var i suma 1, y se sale fuera del for, al scope de 
la funcion */
// el for se ejecuto 5 veces, pero cada que se ejecuto, el valor de 'var i' se reasignó
function printNumbers() {

var i = 0
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

var i = 1
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

var i = 2
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

var i = 3
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

var i = 4
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

//como var i se salio cada vez, al valor final de i va a ser var i = 4
/*El ciclo for se acaba, el callstack se desocupa, entra en accion el callback queue,
con 10 ordenes pendientes de console.log, cuando estas se imprimen, encontraran cada vez
esto: */
//ultimo valor del for es 4
function printNumbers() {
	var i = 4;
	/*for (var i = 0; i < 5; i++)*/ {
		setTimeout(
      function printer() {
	      console.log(i);
	    } ,100 * i ); }
}
/*porque var i termina siendo 4, ya que al escapar al scope de funcion y no estar en el 
y no estar en el scope de bloque del ciclo, esta, se reasigno cada vez. Quedamos con
un unico binding de 'var i' que vale '4'*/

//con let pasa diferente:
//cada valor de let i, itero y se quedo independiente dentro del scope de bloque.
/*El ciclo for se acaba, el callstack se desocupa, entra en accion el callback queue,
con 10 ordenes pendientes de console.log, cuando estas se imprimen, encontraran cada vez
esto: */

function printNumbers() {

for (i = 0; i < 5; i++) {
	let i = 0
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

for (i = 0; i < 5; i++) {
		let i = 1
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

for (i = 0; i < 5; i++) {
		let i = 2
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

for (i = 0; i < 5; i++) {
		let i = 3
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

for (i = 0; i < 5; i++) {
		let i = 4
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}
//todo esto pasa por dentras
--

Para los que no les quedo claro por que imprime //0 1 2 3 4 5 6 7 8 9, como explica el profesor aqui, tenemos tres entornos léxicos, el entorno léxico anotherFunction y el entorno léxico for y entorno léxico setTimeout, lo que esta pasando es que en la primera iteracion en el entorno léxico del setTimeout, estamos imprimiendo i, pero como i no existe en ese entorno léxico pasaríamos a buscarlo en el siguiente entorno léxico el cual seria el del for, entonces iteracion i = 0, entonces actualiza el valor de i para el entorno léxico del setTimeout (i = 0), luego se ejecuta la segunda iteracion, vemos que en el entorno lexico del setTimeout se vuelve a imprimir i, pero para este NUEVO(es un nueva función) entorno léxico setTimeout y no existe, por tanto se vuelve a subir un nivel y vemos que en el entorno léxico del for esta vez i = 1, entonces recuperamos ese valor para el entorno lexico de setTimeout i = 1, y así sucesivamente //0 1 2 3 4 5 6 7 8 9
const anotherFunction = () => {
for (let i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i)
}, 1000)
}
}
anotherFunction()

Lo que entiendo por bloque en JS es todo aquello que esté entre llaves {}

Block Scope: Un bloque de código es un pedazo de estructura de código. Dentro del bloque se pueden crear variables ( var , let o const ), sin embargo éstas variables solamente habitan en el bloque de código y pueden acceder a los elementos el ámbito en que se encuentran.
·
·
Con asignación de var, ámbito de función.
Con asignación de let & const, ámbito de bloque.

Te confundiste un poco al final explicando que banana es lo primero que se imprime que es el console del bloque pero a ti se te perdona todo Oscar, eres un Crack !

Var es una asignación del Scope local dentro de una funcion, pero let y const solo tienen un scope de bloque

Muy útil el **let** para el *for*! Era una duda que me había quedado del curso de fundamentos de JavaScript cuando el profesor hizo ese cambio.

Uff en esta clase acabo de aprender lo peligroso que pueden llegar a ser las variables con var si no se le da un buen manejo.

El hoisting de la variables definidas con var, muy interesante como se comporta el lenguaje. En el curso profesional de js tambien lo vemos un poco por encima

bien

con let y const solo podemos acceder dentro de los bloques.

Cuando declaramos una variable let o const dentro de un bloque, el alcance o scope que tendrá será sólo dentro de ese bloque.

🧐 luego de haber visto el vídeo más de 2 veces, ejecutado el código un par de veces más, visto los vídeos compartidos por los compañeros de otros canales explicando las diferencias entre var, let y const, y otra vez ejecutado el código con sus variaciones en Chrome y utilizando el devtools con breakpoints … una cosa y solo una me queda claro:

NO HAY QUE USAR VAR! 🤪

(alguien que me explique porqué en el ejm, el índice definido con var, imprime las tantas veces el último valor del ciclo!!!) 🤯

Todo el código que este dentro de llaves se le denomina bloque.

Cool.

Importante cada vez que se pueda realizar la declaracion de nuestras variables al inicio del documento con let, de esta manera no podremos redeclararla dentro del programa pero si utilizarla detro de los scopes locales.

La declaración de una variable como VAR, obtiene el scope de la función, no del bloque, por ésta razón podemos acceder a ella fuera del bloque de código.

No usen var!

No me quedo claro por que se imprime el 10 todas las veces con el setTimeOut?

Con var solo se muestra el 10 porque se va re-asignando con cada aumento del ciclo for, recuerden que var puede ser reasignada pero let no. Es por esto que establecer la variable como let es la solución.

En el último ejemplo, algo que no entendía bien y que se que yo no puedo ser el único que se saco de onda con esto es que el “setTimeout” se manda a llamar 10 veces mucho muy rápido en cada iteración, osea, se ejecuta 1 vez y por cuestión del eventLoop, se queda la instrucción de que en 1000 milisegundos se escriba el log en consola del valor que tiene " i ", entonces ya llegados los 1000 milisegundos del primer setTimeout, el valor de " i " llego hasta 10, porque se reasigno en cada ciclo del for hasta llegar a 10, es por eso que imprime puros 10, porque al accesar a la sección de la memoria donde se guarda el valor " i " tiene 10.

Caso contrario con let, porque se van guardando los valores en cada iteración, se puede decir que llegamos a tener 10 veces la variable " i " por cada ciclo del for, que es lo que normalmente nosotros esperamos, que en cada ciclo haga algo nuestra función con el valor actual de los datos.

comparto codigo de la clase:


// Block Scope
const fruit = () => {
    if (true) {
        var  fruit1 = 'apple';
        let  fruit2 = 'banana';
        const  fruit3 = 'orange';
   }
    console.log(fruit1);
    console.log(fruit2); // no se puede acceder porque esta fuera del bloque
    console.log(fruit3); // no se puede acceder porque esta fuera del bloque
}
fruit();

// USO LET
let x=1;
{
    let x=2;
    console.log(x);  // se nuestra "2" se define en el bloque
}
console.log(x); //nuestra "1" primera definicion

// USO VAR
var x=1;
{
    var x=2;
    console.log(x);  // se nuestra "2" por ultima definicion
}
console.log(x); // se nuestra "2" por ultima definicion

// funcion que trabajo en loop basado asignacion de var y  loop

// uso var
const anotherFunction = () => {
    for (var i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log (i);
        }, 1000)
    }
};
anotherFunction(); //ejeucuta 10 veces el valor de 10 porq es el ultimo valor asignado

// uso let
const anotherFunction = () => {
    for (let i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log (i);
        }, 1000)
    }
};
anotherFunction();  //cada uno de los pasos que se incrementa

Por aca dejo mi código:

if (true) {
  var fruit1 = "apple";
  let fruit2 = "banana";
  const fruit3 = "kiwi";
  console.log(fruit2);
  console.log(fruit3);
}
console.log(fruit1);

let x = 1;
{
  let x = 2;
  console.log("let", x);
}
console.log("let", x);

var y = 1;
{
  var y = 2;
  console.log("var", y);
}
console.log("var", y);

const func1 = () => {
  // Que no uses VAR miserable sabandija!!!!!!!
  for (var index = 0; index < 10; index++) {
    setTimeout(() => {
      console.log(index);
    }, 1000)
  }
  for (let index = 0; index < 10; index++) {
    setTimeout(() => {
      console.log(index);
    }, 1000)
  }
}
func1();

Lo que vamos a ver es cada uno de los pasos que esta intentando desde 0 … 9 y de esta forma nosotros estamos entendiendo la forma de llevar el Scope Local en formato de bloque a todos nuestros bloques de código.

A lo que estoy entendiendo sea donde sea que se declare la palabra reservada “var” es como si fuera una variable global

🤯🤯🤯🤯🤯

Entonces creo que la mejor forma de trabajar con el ciclo for es usando let, para evitar problemas…

const frutas =()=>{
  if (true){
    //las variables de tipo var tienen un function scope dentro de un bloque
    var fruta1 ='apple';
    //las variables let y const tienen un block scope
    let fruta2 ='banana';
    const fruta3 ='kiwi';
    console.log(`${fruta2} ${fruta3}`);
  }
console.log(`${fruta1} `);
}
  
frutas();
//let
let x =1;//<= Esta variable existe en el global, pero no en el block
{
  let x =2;//<= Esta variable solo existe en el block scope, por eso no presenta problema
  console.log(x);//<=Imprimimos la  variable dentro del bloque
}
console.log(x);//<=Imprimimos la varible golobal.
//var
var x =1;//<= Esta variable existe en el global
{
  var x =2;//<= Esta variable es la misma del global y se reescribe en esta linea
  console.log(x);//<=Imprimimos la  variable dentro del bloque, que es la misma del global
}
console.log(x);//<=Imprimimos la varible golobal.(

const funcionIteracion=()=>{
  //La variable se va a sobreescribir hasta tomar el valor de 10
  for (var i=0;i<10;i++){
    setTimeout(()=>{//Esto se ejecuta  1SEGUNDO DESPUES de acabar el for
      console.log(i);
    },1000)
  }
}
funcionIteracion();

const funcionIteracion=()=>{
  //La variable recuerda el valor que tenia 
  for (let i=0;i<10;i++){
    setTimeout(()=>{//Esto se ejecuta  1SEGUNDO DESPUES de cada iteracion
      console.log(i);
    },1000)
  }
}
funcionIteracion();

Creo yo que este código lo explica muy bien c:

//Block Scope con var 

const fruits = function () {
  if (true) {
    var fruit1 = 'Apple'
    var fruit2 = 'Banana'
    var fruit3 = 'Kiwii'
  }
  console.log(fruit1)
  console.log(fruit2)
  console.log(fruit3)
}

freuits() // Va a devolver los valores de las 3 variables

// Block Scope con let y const

const fruits2 = function () {
  if (true) {
    var fruit1 = 'Apple'
    let fruit2 = 'Banana'
    const fruit3 = 'Kiwii'
  }
  console.log(fruit1)
  console.log(fruit2)
  console.log(fruit3)
}

//Solo devolvera el valor de la variable con var,
//ya que esta solo ocupa un scope de funcion y las demas de bloque```

Mis apuntes (4) 😃

// 🧱 Block scope

//Block scope con var, let y const
const fruits = () => {
  if (true) {
    var fruit1 = "apple"; // 🏭 Se asgina al scope de la funcion
    let fruit2 = "banana"; // 🧱 Se asigna al scope del bloque
    const fruit3 = "kiwi"; // 🧱 Se asigna al scope del bloque

    console.log(fruit2); //🧱
    console.log(fruit3); //🧱
  }
  console.log(fruit1); // 🏭
};

fruits();

// Con let respeto el 🧱 block scope
let x = 1;
{
  let x = 2;
  console.log(x);
}
console.log(x);

// Con var no se respeta el bloque (🌎 global scope)
var x = 1;
{
  var x = 2;
  console.log(x);
}
console.log(x);

// Es mas amigable usar let en vez de var en un ➿ bucle
//let
const anotherFunction = () => {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i); //Resultado 0-9
    }, 1000);
  }
};

anotherFunction();

//var
const anotherFunction = () => {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i); //Resultado 10 x 10 veces
    }, 1000);
  }
};

anotherFunction();

Este scope solo funciona con let o const, este scope permite su alcance dentro del bloque en el que se instancia ya sea un bucle, un if o un bloque forzado (las llaves puestas solas {} con el único propósito de generar un nuevo scope)
P.D. las variables declaradas en los parámetros de una función o bucle cuentan dentro de estos por ejemplo for(let i = 0; i<10;i++)

Scope bloque
Este scope solo funciona con let o const, este scope permite su alcance dentro del bloque en el que se instancia ya sea un bucle, un if o un bloque forzado (las llaves puestas solas {} con el único propósito de generar un nuevo scope)
P.D. las variables declaradas en los parámetros de una función o bucle cuentan dentro de estos por ejemplo for(let i = 0; i<10;i++)

¿Qué es un bloque en JS?


Mientras llamemos sobre una llave esa variable va estar guardada dentro de un bloque, puede ser una function, un if, for, etc…

Si ejecutamos la siguiente función al ser declaradas con var vamos a poder acceder a los valores de esas variables fuera del bloque, ya que var es una asignación del scope local dentro de la function.

const fruits = () => {
    if (true) {
        var f1 = 'apple'
        var f2 = 'banana'
        var f3 = 'kiwi'
    }

    console.log(f1)
    console.log(f2)
    console.log(f3)
}

fruits();

Pero con let y const no vamos a poder acceder, ya que estos se establecen dentro del bloque.

const fruits = () => {
    if (true) {
        var f1 = 'apple'
        let f2 = 'banana'
        const f3 = 'kiwi'
    }

    console.log(f1)
    console.log(f2)
    console.log(f3)
}

fruits();

Para que funcione el anterior código tiene que ser declarado así:

const fruits = () => {
    if (true) {
        var f1 = 'apple';
        let f2 = 'banana';
        const f3 = 'kiwi';
        console.log(f2)
        console.log(f3)
    }
    console.log(f1)
}

fruits();

También podemos asignar una variable con el mismo nombre y no dar error cuando una esta en el scope global y otra dentro de un bloque

let x = 1
{
    let x = 2
    console.log(x)
}
console.log(x)

Al declarar la variable del for con var y tratar de visualizar el valor de está, veremos que nos muestra el último valor que recorre nuestro for. La solución más simple para esto es asignar la variable let para ese scope de bloque

const anotherFunction = () => {
    for (var i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log(i)
        }, 1000)
    }
}
anotherFunction()

const anotherFunction = () => {
    for (let i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log(i)
        }, 1000)
    }
}
anotherFunction()
const fruits = () => {
    if(true){
        var fruits1 = 'apple';  // scope global
        let fruits2 = 'banana'; // scope de bloque
        const fruits3 = 'kiwi'; // scope de bloque
    }
    console.log(fruits1);
    console.log(fruits2);
    console.log(fruits3);
}

fruits();```

En pocas palabras, la palabra reservada var se debe dejar de usar y solo usar let y const

Confieso que me costo un poco entender porque mostraba 10 vcs 10, así que acá les dejo la explicación

Link de exp

Por si a alguno le interesa, acá les dejo este link de Philip Roberts, el cual hace una de las mejores explicaciones que vi de event loop

const fruit = ()=> {
/*
    Para el scope de bloques debemos de tener en cuenta que si manejamos las variables 
    con la palabra reservada var obtendremos como resultado la referencia a una variable
    local a la funcion (en este caso fruit) pero, si declaramos variables con let
    obtendremos como resultado una referencia a una variable local al bloque, es decir
    terminando el bloque de ejecucion (en este caso el condicional if), la variable deja de existir
*/

    if(true){
        var manzana = "manzana";
        let pera = "pera";
        const guayaba = "guayaba";
    }

    console.log(manzana);
    console.log(pera);
    console.log(guayaba);
}

Para profundizar más sobre este tema les recomiendo este enlace https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/scope%20%26%20closures/ch5.md que hace parte del libro You Don’t Know JS

Cuando declaramos con let y const el scope de la variable es el bloque (no la función), en este caso sólo existen dentro del if.

El scope de bloque esta delimitado por las llaves, por ejemplo, el bloque de código de un if.
Para usar el scope de bloque se debe declarar la variable con let o const, de lo contrario, con var se podrá acceder a la variable en un scope global.
Con var, además de poder acceder a la variable de forma global, también es posible cambiar el valor de forma global. Por ejemplo, si cambiamos el valor de la variable x dentro de un bloque de código, el valor también cambiará fuera del bloque.

Entonces a ver si entendí: con var lo que sucede es que debido al hoisting el interprete eleva a la variable declarada con var, esta queda guardada en el scope global teniendo un mismo entorno léxico y por cada iteración del for el valor se actualiza y cuando el setTimeOut se ejecuta toma el último valor (10).
Y con let lo que está sucediendo es que cada valor que toma “i” es un entorno diferente entonces al ejecutarse el setTimeOut toma el valor en ese momento de la variable “i” que corresponden a distintos momentos del código.
Algo más para agregar? Alguna corrección a lo que escribí?

Para terminar de complementar este modulo del Scope en JS, les recomiendo mucho el video de Sasha en su canal Cocina del codigo, aunque Oscar lo explica bien, tiene pequeñitos errores que puede confundir a un principiante, en su lugar Sasha lo explica de una manera mucho mas didactiva y dinamica, lo cual es mejor visualmente con ejemplos y referencias claras. Les he dejado el video arrriba en el texto, ‘La cocina del codigo’.

Una buena forma de entender el problema del ciclo for, es entendiendo los procesos asincrónicos de Javascript, pásense por el curso de fundamentos de javascript y ahí explican muy bien este tema

¿Cual es la diferencia entre el ámbito léxico y el scope local?

good video

Les dejo el código de la clase.

const fruits = () =>{
    if(true){
        //Cuando declaramos estas variables con var, podemos acceder a ellas
        //fuera del if, dentro del scope de la función
        // var fruits1 = 'apple';
        // var fruits2 = 'banana';
        // var fruits3 = 'kiwi';
        //En cambio cuando las declaramos con let, no podemos acceder a ellas
        //fuera del bloque del if
        let fruits1 = 'apple';
        let fruits2 = 'banana';
        let fruits3 = 'kiwi';
    }
    console.log(fruits1);
    console.log(fruits2);
    console.log(fruits3);
}

fruits();

//Lo que sucede acá es que el console.log dentro de bloque muestra lo que se asigna a la variable que está en el mismo scope.
let x = 1;
{
    let x = 2;
    console.log(x);
}
console.log(x);

//El mismo ejemplo pero cambiando los let por var
//Dentro del bloque de código se reasigna el valor de x, dando como resultado que los dos console.log muestren el último valor asignado de la variable, en este caso 2.
var x = 1;
{
    var x = 2;
    console.log(x);
}
console.log(x);


//Se ejecuta el número 10, esto por razón del hoisting, esto se puede solucionar cambiando var por let.
const anotherFunction =() =>{
    for (var i = 0; 1 < 10; i++){
        setTimeout(() => {
            console.log(i);
        }, 1000);
    }
}

anotherFunction();```

Buen complemento para esta clase:

EL SCOPE en JAVASCRIPT | JS en ESPAÑOL

La verdad prefiero no utilizar var en lo posible.

Var dentro de los bloques de código siempre toma como valor la última declaración hecha.
Mientras que let y const no se reescriben.

Tuve curiosidad de por que al instructor cuando ejecutaba la función llamada anotherFunction con un for inicializado con la palabra reservada var se mostraba el numero diez en consola, entonces decidí investigar un poco; la respuesta tiene que ver con el Hoisting y Asincronía o EventLoop.
.
Esto es algo como lo que tiene el instructor:

function functionName() {
	// Para este ejemplo declarare que el for solo de 3 "vueltas", es decir la condición sera: i < 3.
	for(var i = 0; i < 3; i++) {
		setTimeout(function() {
			console.log(i);
		}, 1000);
	}
	
	console.log('El valor final de "i" es: ' + i);
}

El hoisting hace que la variable con el nombre i dentro del for se “eleve” y sea asignada en memoria, por lo tanto a lo último se estará reasignando el ultimo incremento que tuvo y se podrá acceder a ella en cualquier punto dentro de la función functionName.

function functionName() {
	var i;
	for(i = 0; i < 3; i++) {
		setTimeout(function() {
			console.log(i);
		}, 1000);
	}
	// Este console.log podra acceder a i aun afuera del for, esto por que la variable i fue declarada y asignada antes que todo en tiempo de ejecución (hoisting).
	console.log('El valor final de "i" es: ' + i);
}

Entonces asumiendo eso y respondiendo a la pregunta de por que el console.log que esta adentro del setTimout solo imprime el valor final de i llegue a la siguiente conclusión:
.

  1. El for estará ejecutándose en el Call Stack mientras la condición propuesta en el for (i < 3) se cumpla, por tanto también se ejecutara el setTimeout cada que la condición del for sea verdadera, sin embargo hay que recordar que el setTimeout es una función del navegador, entonces el setTimeout pasara a ejecutarse en “segundo plano” y una vez que los tiempos de espera definidos de los setTimeout se cumplan, estos pasaran al Callback Queue.
    .
  2. Una vez que la condición del for ya no se cumpla, pasara a ejecutar el console.log que mostrará el valor final que para entonces será igual a 3 por que el for ya estuvo mutando el valor con cada incremento (i++).
    .
  3. Posteriormente ya cuando el Call Stack esta vació pasaran a ejecutarse el callback de cada setTimeout que a su vez ejecutan un console.log imprimiendo el valor de la variable i, recordando que i ya tiene el valor final de 3 por que se había incrementado en uno en cada “vuelta” que daba el for.
    .
    Capture.JPG
    .
    Referencias:
    JavaScript closure inside loops – simple practical example

    Is it best to use “var” or “let” in for loop iterations or does it even matter?
    .

Un videíto increíble de var, let y const por si gustan entender mejor el scope

.
var.png
https://www.youtube.com/watch?v=ojrvxYcKeYg

Con var , tiene un scope de función y solo un enlace compartido para todas sus iteraciones de bucle, es decir, i en cada callback setTimeout significa la misma variable que finalmente es igual a 6 después de que finaliza la iteración del bucle.

Con let tener un scope de bloque y cuando se utiliza en el ciclo for obtiene un enlace nuevo para cada iteración, es decir, el i en cada callback setTimeout significa una variable diferente, cada una de las cuales tiene un valor diferente: la primera es 0, la el siguiente es 1 etc.

Ahora, ¿Pero por qué me devuelve 10 veces 10? ¿No debería devolverme 10 veces 9?
veamos la declaración del ciclo for:

for (var i = 0; i < 10; i++) {
	...
}

El ciclo for termina cuando la condición (i < 10) sea falsa, osea que mientras sea verdadera el recorrerá el ciclo. La variable i aumentará su valor en 1 (i++) por cada iteración, osea que tomará estos valores: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10). Toma el 10 porque es ese el valor donde la condición (i < 10) es falsa puesto que 10 no es menor que 10, si no que es igual… y el ciclo termina.
Espero haberles ayudado y que hayan aclarado sus dudas!

Si todavía se les complica entender, les dejo el enlace de la explicación del profesor Richard!!

Les dejo esta infografia como breve resumen de lo que es el Scope. espero sea util 😃
scope1.jpg

El block scope gue algo que me rompió cuando lo aprendí, porque si no me equivoco, no hay más lenguajes que lo tengan jaja (o igual si) pero aún no los conozco

Para explicar un poco mejor qué fue lo que sucedió con el timeOut, al declarar con “var” la variable “i” dentro del for, lo que estamos haciendo es declarar una variable global llamada “i”, y con cada iteración del for estamos sobreescribiendo esa variable, el for del 1 al 10 se ejecuta en menos de un segundo, es decir, una computadora es rápida ejecutando código, pero el setTimeout se ejecutará después de un segundo, JavaScript NO se va a quedar esperando que cada setTimeout se ejecute, simplemente JavaScript va a ver que hay un setTimeout y lo va a poner en su cola de tareas (Ver el curso de asíncronismo con JavaScript y el curso profesional de JavaScript para entender esto mejor), el caso es que, cuando pasa un segundo, los 10 setTimeouts que JavaScript puso en cola (Uno por cada iteración) se ejecutan, y como “i” es una variable global que fue sobreescrita, se quedo con el último valor de 10 (Porque aunque la condición del último ciclo no se cumplió, la variable si fue asignada para poder evaluar la condición), y es por eso que todos los setTimeouts miran el valor de la variable y todos acaban obteniendo “10”, con let, como saben, no se puede sobreescribir la variable, y tenemos un “let” diferente por cada iteración (Imaginen que cada iteración es un bloque de código totalmente diferente), entonces, cada setTimeout agarra el “let” que está dentro de su propio bloque de código, y como es único gracias al scope, ahí si que se imprimen del 1 al 9:D!

En for no debemos utilizar var i = 0 porque al imprimir va imprimir 10 veces el ultimo valor, ejemplo:

//for no debemos utilizar var sino let
const anotherFunction = () => {
  for (var i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i)
    }, 1000)
  }
}
anotherFunction()

Va imprimir: 10 10 10 10 10 10 10 10 10 10
**Pero con let: **

const anotherFunction = () => {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i)
    }, 1000)
  }
}
anotherFunction()

Va imprimir: 0 1 2 3 4 5 6 7 8 9

Dentro de una función podemos tener un bloque de código, por ejemplo: un if, mientras lo llamamos sobre una llave estará guardado dentro de un bloque.

Si definimos un elemento con var podemos acceder en todos los elementos de la función, si lo llamamos fuera del bloque donde está, vamos a poder acceder a ese elemento.

Con let y const no vamos a poder acceder a ellos porque se establecen dentro del bloque, solo se puede acceder a ellos dentro de ese bloque.

muy importante y ultil el uso de let.

const fruit = () => {
    if (true) {
        //De esta forma puedo acceder a las variables declaradas dentro del IF, se puede acceder a ellas fuera del IF
        // var fruit1 = 'Apple';
        // var fruit2 = 'Banana';
        // var fruit3 = 'Kiwi';
        //cuando declaro las variables con LET y/o CONST dentro del IF, son locales para el bloque de codigo del IF
        //y no las puede acceder fuera del bloque IF, asi esten en la misma funcion
        var fruit1 = 'Apple';
        let fruit2 = 'Banana';
        const fruit3 = 'Kiwi';

        console.log(fruit2);
        console.log(fruit3);
    }

    console.log(fruit1);
    // console.log(fruit2);
    // console.log(fruit3);

    //para poder acceder a las variables fruit2 y fruit3, debo colocarlas dentro del bloque de codigo donde fueron declaradas , en este caso IF
}

fruit();

// //Esta variable esta en ambito globa,
// let x = 1;
// {
//     //esta variable esta en ambito local, 
//     //y asi tenga el mismo nombre de la del ambito local, mantienen cada una su valor
//     let x = 2;
//     console.log(x);
// }
// console.log(x);

var x = 1;
{
    //esta variable esta en ambito local, 
    //y asi tenga el mismo nombre de la del ambito local, 
    //la asignacion hecha del ambito local se transfiere a la variable global
    var x = 2;
    console.log(x);
}
console.log(x);


// De esta forma solo muestra el valor diez, aunque lo muestra 10 veces, 
//esto ocurre porque nos muestra el ultimo valor de la variable
// dentro del ambito del ciclo for esta asignado el diez.
// const anotherFunction = () => {
//     for (var i = 0; i < 10; i++) {
//         setTimeout(() => {
//             console.log (i);
//         }, 1000)
//     }
// };

//al cambiar la forma de asignacion de declaraciòn de la variaable dentro del FOR,
//y usar LET, no muestra el resultado esperado.
const anotherFunction = () => {
    for (let i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log (i);
        }, 1000)
    }
};

anotherFunction();

https://platzi.com/clases/1807-scope/25874-block-scope/?time=417 Esta fue una pregunta de entrevista de screening, define la salida de una ciclo usando var y let dentro de un setTimeout ¿cual es la salida? 😉

Oscar lo explica perfecto pero por si gustan otro ejemplo adicional recomiendo este video: https://youtu.be/kQwaq2MMZ-Y

Siempre let nunca inlet😁

me exploto la cabeza con el ejemplo del for 😮

Ok!! no sabía eso de quel scope del var aplica dentro de una función y que el scope del let y const aplica dentro de un bloque, mind blowing!

por lo que entendí, las variables declaradas con var no toman en cuenta el scope de un bloque y se lo “saltan” por así decirlo y lo que hacen es asignar su scope a la función mas cercana o si no existe una función lo hace de manera global.

var es un rebelde sin causa, le sabe a cake las delimitaciones por bloque! 😂

Entonces podríamos ahorrarnos todo esto simplemente usando let y const :3

Un pequeño repaso de los cursos de básico y fundamentos de javascript

A mi me sirvio entenderlo asi
recordemos que al declarar una variable con var esta puede reevaluarse con otro valor y que cuando declaramos una variable lo que estamos haciendo es decirle a la computadora “guardeme este valor en memoria” , entonces cuando paso al console.log(i) lo que hizo fue enviar esta orden a una “lista de tareas” que se ejecutara cuando ya termine de leer todo el codigo.
Entonces cada que realizaba un ciclo, este le decia " mandeme esta funcion a la lista de tareas y la ejecuta ahorita" entonces teniamos 10 veces console.log(i) en espera, cuando termino de ejecutarse todo el codigo, este le dijo a memoria “Cuanto es el valor de i?” y como se declaro con var, fue como si se estuviera reescribiendo en cada ciclo, entonces en memoria lo unico que tenia era que i = 10, por eso imprimio 10 veces el mismo valor.
Ahora ¿Qué pasa con let?¿Por qué si funciona con esto?
Realiza exactamente lo mismo ciclo, pero esta vez en memoria, hay 10 numeros guardados por que let solo permite definir una variable con un valor, no permite reevaluarla, entonces se ejecuto el primer console.log(i) este tomo el primer valor de i que era 1 y luego ocurrio lo mismo con los demas console, pasando uno a uno los valores de i

Espero le sirva a alguien

BLOCK SCOPE APUNTES

//Bloque de codigo es aquel que esta establecido dentro de unas llaves {}

const fruit = () => {

    if(true){

        var fruits = 'apple';
        var fruits2 = 'banana';
        var fruits3 = 'kiwi';

    }

    //vamos a acceder a las variables del if fuera del bloque del if
    console.log(fruits,fruits2,fruits3); // apple banana kiwi

    //---Cuando definimos variables en un bloque distinto con var

    /* Podre acceder a las variables sin problema alguno y podremos accederlos
       Ya que estan establecido dentro del scope de la funcion y esto significa
       El que podamos accederlos en cualquier parte del scope de la funcion */

    // Con let y const

    // No podremos acceder a ellas si estan establecidas con let y const
    // Porque ellas se establecen dentro del bloque en el que estan y solo
    // podran ser accedidas dentro de ese bloque
}

fruit()

let x = 1;

{

    let x = 2;
    console.log(x); //2
}

    console.log(x); //1

//Mismo ejemplo con var 

var x = 1;

{
//Lo que sucede aqui es que el valor reasignado a x tambien cambio en la variable global
// Si queremos declarar un valor debemos hacerlo con let para que este valor
  // trabaje solo en el scope de ese bloque 
    var x = 2;
    console.log(x); //2
}

    console.log(x); //2

const anotherFunction = () => {


    for(let i = 0; i < 10; i++){

        setTimeout(()=>{

            console.log(i);
        }, 1000)


    }
}

anotherFunction(); // al  imprimir la variable i que esta declarada con var
                    // IMPRIME 10 LAS 10 VECES
// Nos muestra este valor ya que esta accediendo al ultimo valor que recorre 
// El for

// La solucion es asignando la variable i con let```

Y lo bueno es que VSC me lo dice de antemano

Screen Shot 2020-12-24 at 10.42.50.png

Por si alguien necesita tener mas claro el temas les dejo este link https://www.youtube.com/watch?v=cTfGyVFrLxQ&t=29s

sigo sin entender el ejemplo del for y el setTimeout.

traté de ejemplificarlo en mi cabeza llevándol al proceso que haría el engine de JS (callstack, callback queue, event loop, etc), pero me sigue sin cuadrar algunas cosas

estuvo muy bien explicado qué es un bloque en JavaScript y su relación con el Scope

excelente clase!

Cuando declaramos una variable tipo var dentro de una función su scope va a poder ser accedido desde cualquier bloque dentro de la función. Let y const por otro lado solo funcionaran dentro del bloque declarado.

supongo que este imprime 10 veces el 10 porque espera al código por el setTimeOut lo que significa que primero ejecuta la función del for, y esta al ser ejecutada pues va a ir sobrescribiendo sus variables, primero var i equivale 0 después 1 después 2 hasta llegar a 10, después de esto ejecuta el setTimeOut del console.log osea el 10 y de nuevo vuelve a hacer este paso vuelve al for sobreescribe las variables y ejecuta el 10 y asi hasta ejecutarlo las 10 veces. pueden hacer la prueba quitando el setTimeOut con el var y notaran que si imprime el ciclo de la manera correcta.

Var === Caos.

Block Scope
A diferencia del scope local este scope está limitado al bloque de código donde fue definida la variable. Desde ECMAScript 6 contamos con los keyword let y const los cuales nos permiten tener un scope de bloque, esto quiere decir que las variables solo van a vivir dentro del bloque de código correspondiente.

Para los que como yo son nuevos en JavaScript y no entendieron muy bien la sintaxis del bucle for del ejemplo del profesor:

The for loop has the following syntax:

for (statement 1; statement 2; statement 3) {

}

Statement 1 is executed (one time) before the execution of the code block.

Statement 2 defines the condition for executing the code block.

Statement 3 is executed (every time) after the code block has been executed.

hace falta un cuadro comparativo de todos los scopes

conclusion tener cuidado al asignar con var

Lo que sucede en realidad es que como javascript es asíncrono entonces hasta que no termine la iteración del For no entraría la función setTimeout

Sabemos que al tener elementos dentro de un bloque de codigo estos podrian funcionar como un scope global, pero si tenemos un BLOQUE dentro de una funcion, esto sera un caso especial, todo depende de la palabra clave que usemos. Si usamos LET o CONST solo funcionaran en el bloque de codigo que seran declarados PERO var si podra ser utilizada y manipulada por LA FUNCION.

let x = 1;
{ 
	let x = 2;
	console.log(x); --> 2
}
console.log(x) --> 1

Scope local en bloques : aplica para las variables declaradas dentro de un bloque(if, for, while, etc.), al declarar una variable con var dentro de un bloque esta si puede ser accedida fuera del bloque porque trabaja dentro del ámbito de la función en cambio al declarar con let y const no se puede porque trabajan únicamente dentro del ámbito bloque.

// Local scope in blocks

const fruits = () => {
  if (true) {
    var fruits1 = "apple";
    // var fruits2 = "banana";
    // var fruits3 = "kiwi";

    let fruits2 = "banana";
    const fruits3 = "kiwi";

    console.log(fruits2);
    console.log(fruits3);
  }

  console.log(fruits1);
  // console.log(fruits2);
  // console.log(fruits3);
};

fruits();

let x = 1;

{
  let x = 2;
  console.log(x);
}
console.log(x);

var x = 1;

{
  var x = 2;
  console.log(x);
}
console.log(x);

const anotherFunction = () => {
  for (var i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i);
    }, 1000);
  }
};

anotherFunction();

const anotherFunction = () => {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i);
    }, 1000);
  }
};

anotherFunction();

Si desean las notas que voy a ir tomando de los cursos las voy a publicar en un repositorio, se las comparto estas son las de este curso:

https://github.com/patogalarzar/code-notes/tree/main/Closures-Scope

Cuando declaramos con let y const el scope de la variable es el bloque (no la función), en este caso sólo existen dentro del if.

Cuando declaramos con let y const el scope de la variable es el bloque (no la función), en este caso sólo existen dentro del if.

lamentablemente sigue llamando ‘asignacion’ a lo que es ‘declaracion’, pero no hay que confundir ese concepto.

Luego de darle al coco un rato, esta fue la manera en que pude organizar las cosas en mi mente:
//

function printNumbers() {
	for (var i = 0; i < 5; i++) {
		setTimeout(
      function printer() {
	      console.log(i);
	    } ,100 * i ); }
}

printNumbers();

//ocurre el primer ciclo

function printNumbers() {
	var i
	for (i = 0; i < 5; i++) {
		i = 0;    //esto se sale para arriba, afuera del for
		setTimeout(
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}
}

/*se ejecuta con 0 pero la condicion del ciclo for la ejecuta el navegador y la pone en 
el callstack, mientras setTimeout pone su funcion de console.log en el callback queue po
ende las ordenes de console.log estan lista para ejecutarse solo despues que lo que esta
en el callstack que es la condicion for con los valore de i*/

//Todo es culpa del hoisting, porque VAR tiene scope de Funcion y let scope de Bloque
//Cuando el codigo itera va a pasar lo siguiente 
//se ejecuta cada bloque for 

var i = 0
/*la variable i que se salio por el hoisting, era undefined, pero luego en el ciclo
for fue asiganada como 0 */
//mientras, por el otro lado, se agenda un console.log en el callback queue
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}
/*como cada vez que el ciclo corre, var i suma 1, y se sale fuera del for, al scope de 
la funcion */
// el for se ejecuto 5 veces, pero cada que se ejecuto, el valor de 'var i' se reasignó
function printNumbers() {

var i = 0
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

var i = 1
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

var i = 2
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

var i = 3
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

var i = 4
for (i = 0; i < 5; i++) {
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

//como var i se salio cada vez, al valor final de i va a ser var i = 4
/*El ciclo for se acaba, el callstack se desocupa, entra en accion el callback queue,
con 10 ordenes pendientes de console.log, cuando estas se imprimen, encontraran cada vez
esto: */
//ultimo valor del for es 4
function printNumbers() {
	var i = 4;
	/*for (var i = 0; i < 5; i++)*/ {
		setTimeout(
      function printer() {
	      console.log(i);
	    } ,100 * i ); }
}
/*porque var i termina siendo 4, ya que al escapar al scope de funcion y no estar en el 
y no estar en el scope de bloque del ciclo, esta, se reasigno cada vez. Quedamos con
un unico binding de 'var i' que vale '4'*/

//con let pasa diferente:
//cada valor de let i, itero y se quedo independiente dentro del scope de bloque.
/*El ciclo for se acaba, el callstack se desocupa, entra en accion el callback queue,
con 10 ordenes pendientes de console.log, cuando estas se imprimen, encontraran cada vez
esto: */

function printNumbers() {

for (i = 0; i < 5; i++) {
	let i = 0
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

for (i = 0; i < 5; i++) {
		let i = 1
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

for (i = 0; i < 5; i++) {
		let i = 2
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

for (i = 0; i < 5; i++) {
		let i = 3
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}

for (i = 0; i < 5; i++) {
		let i = 4
		setTimeout( 
      function printer() {
	      console.log(i);
	    } ,100 * i ); 
	}
//todo esto pasa por dentras
--

Para los que no les quedo claro por que imprime //0 1 2 3 4 5 6 7 8 9, como explica el profesor aqui, tenemos tres entornos léxicos, el entorno léxico anotherFunction y el entorno léxico for y entorno léxico setTimeout, lo que esta pasando es que en la primera iteracion en el entorno léxico del setTimeout, estamos imprimiendo i, pero como i no existe en ese entorno léxico pasaríamos a buscarlo en el siguiente entorno léxico el cual seria el del for, entonces iteracion i = 0, entonces actualiza el valor de i para el entorno léxico del setTimeout (i = 0), luego se ejecuta la segunda iteracion, vemos que en el entorno lexico del setTimeout se vuelve a imprimir i, pero para este NUEVO(es un nueva función) entorno léxico setTimeout y no existe, por tanto se vuelve a subir un nivel y vemos que en el entorno léxico del for esta vez i = 1, entonces recuperamos ese valor para el entorno lexico de setTimeout i = 1, y así sucesivamente //0 1 2 3 4 5 6 7 8 9
const anotherFunction = () => {
for (let i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i)
}, 1000)
}
}
anotherFunction()

Lo que entiendo por bloque en JS es todo aquello que esté entre llaves {}

Block Scope: Un bloque de código es un pedazo de estructura de código. Dentro del bloque se pueden crear variables ( var , let o const ), sin embargo éstas variables solamente habitan en el bloque de código y pueden acceder a los elementos el ámbito en que se encuentran.
·
·
Con asignación de var, ámbito de función.
Con asignación de let & const, ámbito de bloque.

Te confundiste un poco al final explicando que banana es lo primero que se imprime que es el console del bloque pero a ti se te perdona todo Oscar, eres un Crack !

Var es una asignación del Scope local dentro de una funcion, pero let y const solo tienen un scope de bloque

Muy útil el **let** para el *for*! Era una duda que me había quedado del curso de fundamentos de JavaScript cuando el profesor hizo ese cambio.

Uff en esta clase acabo de aprender lo peligroso que pueden llegar a ser las variables con var si no se le da un buen manejo.

El hoisting de la variables definidas con var, muy interesante como se comporta el lenguaje. En el curso profesional de js tambien lo vemos un poco por encima

bien

con let y const solo podemos acceder dentro de los bloques.

Cuando declaramos una variable let o const dentro de un bloque, el alcance o scope que tendrá será sólo dentro de ese bloque.

🧐 luego de haber visto el vídeo más de 2 veces, ejecutado el código un par de veces más, visto los vídeos compartidos por los compañeros de otros canales explicando las diferencias entre var, let y const, y otra vez ejecutado el código con sus variaciones en Chrome y utilizando el devtools con breakpoints … una cosa y solo una me queda claro:

NO HAY QUE USAR VAR! 🤪

(alguien que me explique porqué en el ejm, el índice definido con var, imprime las tantas veces el último valor del ciclo!!!) 🤯

Todo el código que este dentro de llaves se le denomina bloque.

Cool.

Importante cada vez que se pueda realizar la declaracion de nuestras variables al inicio del documento con let, de esta manera no podremos redeclararla dentro del programa pero si utilizarla detro de los scopes locales.

La declaración de una variable como VAR, obtiene el scope de la función, no del bloque, por ésta razón podemos acceder a ella fuera del bloque de código.

No usen var!

No me quedo claro por que se imprime el 10 todas las veces con el setTimeOut?

Con var solo se muestra el 10 porque se va re-asignando con cada aumento del ciclo for, recuerden que var puede ser reasignada pero let no. Es por esto que establecer la variable como let es la solución.

En el último ejemplo, algo que no entendía bien y que se que yo no puedo ser el único que se saco de onda con esto es que el “setTimeout” se manda a llamar 10 veces mucho muy rápido en cada iteración, osea, se ejecuta 1 vez y por cuestión del eventLoop, se queda la instrucción de que en 1000 milisegundos se escriba el log en consola del valor que tiene " i ", entonces ya llegados los 1000 milisegundos del primer setTimeout, el valor de " i " llego hasta 10, porque se reasigno en cada ciclo del for hasta llegar a 10, es por eso que imprime puros 10, porque al accesar a la sección de la memoria donde se guarda el valor " i " tiene 10.

Caso contrario con let, porque se van guardando los valores en cada iteración, se puede decir que llegamos a tener 10 veces la variable " i " por cada ciclo del for, que es lo que normalmente nosotros esperamos, que en cada ciclo haga algo nuestra función con el valor actual de los datos.

comparto codigo de la clase:


// Block Scope
const fruit = () => {
    if (true) {
        var  fruit1 = 'apple';
        let  fruit2 = 'banana';
        const  fruit3 = 'orange';
   }
    console.log(fruit1);
    console.log(fruit2); // no se puede acceder porque esta fuera del bloque
    console.log(fruit3); // no se puede acceder porque esta fuera del bloque
}
fruit();

// USO LET
let x=1;
{
    let x=2;
    console.log(x);  // se nuestra "2" se define en el bloque
}
console.log(x); //nuestra "1" primera definicion

// USO VAR
var x=1;
{
    var x=2;
    console.log(x);  // se nuestra "2" por ultima definicion
}
console.log(x); // se nuestra "2" por ultima definicion

// funcion que trabajo en loop basado asignacion de var y  loop

// uso var
const anotherFunction = () => {
    for (var i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log (i);
        }, 1000)
    }
};
anotherFunction(); //ejeucuta 10 veces el valor de 10 porq es el ultimo valor asignado

// uso let
const anotherFunction = () => {
    for (let i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log (i);
        }, 1000)
    }
};
anotherFunction();  //cada uno de los pasos que se incrementa

Por aca dejo mi código:

if (true) {
  var fruit1 = "apple";
  let fruit2 = "banana";
  const fruit3 = "kiwi";
  console.log(fruit2);
  console.log(fruit3);
}
console.log(fruit1);

let x = 1;
{
  let x = 2;
  console.log("let", x);
}
console.log("let", x);

var y = 1;
{
  var y = 2;
  console.log("var", y);
}
console.log("var", y);

const func1 = () => {
  // Que no uses VAR miserable sabandija!!!!!!!
  for (var index = 0; index < 10; index++) {
    setTimeout(() => {
      console.log(index);
    }, 1000)
  }
  for (let index = 0; index < 10; index++) {
    setTimeout(() => {
      console.log(index);
    }, 1000)
  }
}
func1();

Lo que vamos a ver es cada uno de los pasos que esta intentando desde 0 … 9 y de esta forma nosotros estamos entendiendo la forma de llevar el Scope Local en formato de bloque a todos nuestros bloques de código.

A lo que estoy entendiendo sea donde sea que se declare la palabra reservada “var” es como si fuera una variable global

🤯🤯🤯🤯🤯

Entonces creo que la mejor forma de trabajar con el ciclo for es usando let, para evitar problemas…

const frutas =()=>{
  if (true){
    //las variables de tipo var tienen un function scope dentro de un bloque
    var fruta1 ='apple';
    //las variables let y const tienen un block scope
    let fruta2 ='banana';
    const fruta3 ='kiwi';
    console.log(`${fruta2} ${fruta3}`);
  }
console.log(`${fruta1} `);
}
  
frutas();
//let
let x =1;//<= Esta variable existe en el global, pero no en el block
{
  let x =2;//<= Esta variable solo existe en el block scope, por eso no presenta problema
  console.log(x);//<=Imprimimos la  variable dentro del bloque
}
console.log(x);//<=Imprimimos la varible golobal.
//var
var x =1;//<= Esta variable existe en el global
{
  var x =2;//<= Esta variable es la misma del global y se reescribe en esta linea
  console.log(x);//<=Imprimimos la  variable dentro del bloque, que es la misma del global
}
console.log(x);//<=Imprimimos la varible golobal.(

const funcionIteracion=()=>{
  //La variable se va a sobreescribir hasta tomar el valor de 10
  for (var i=0;i<10;i++){
    setTimeout(()=>{//Esto se ejecuta  1SEGUNDO DESPUES de acabar el for
      console.log(i);
    },1000)
  }
}
funcionIteracion();

const funcionIteracion=()=>{
  //La variable recuerda el valor que tenia 
  for (let i=0;i<10;i++){
    setTimeout(()=>{//Esto se ejecuta  1SEGUNDO DESPUES de cada iteracion
      console.log(i);
    },1000)
  }
}
funcionIteracion();

Creo yo que este código lo explica muy bien c:

//Block Scope con var 

const fruits = function () {
  if (true) {
    var fruit1 = 'Apple'
    var fruit2 = 'Banana'
    var fruit3 = 'Kiwii'
  }
  console.log(fruit1)
  console.log(fruit2)
  console.log(fruit3)
}

freuits() // Va a devolver los valores de las 3 variables

// Block Scope con let y const

const fruits2 = function () {
  if (true) {
    var fruit1 = 'Apple'
    let fruit2 = 'Banana'
    const fruit3 = 'Kiwii'
  }
  console.log(fruit1)
  console.log(fruit2)
  console.log(fruit3)
}

//Solo devolvera el valor de la variable con var,
//ya que esta solo ocupa un scope de funcion y las demas de bloque```

Mis apuntes (4) 😃

// 🧱 Block scope

//Block scope con var, let y const
const fruits = () => {
  if (true) {
    var fruit1 = "apple"; // 🏭 Se asgina al scope de la funcion
    let fruit2 = "banana"; // 🧱 Se asigna al scope del bloque
    const fruit3 = "kiwi"; // 🧱 Se asigna al scope del bloque

    console.log(fruit2); //🧱
    console.log(fruit3); //🧱
  }
  console.log(fruit1); // 🏭
};

fruits();

// Con let respeto el 🧱 block scope
let x = 1;
{
  let x = 2;
  console.log(x);
}
console.log(x);

// Con var no se respeta el bloque (🌎 global scope)
var x = 1;
{
  var x = 2;
  console.log(x);
}
console.log(x);

// Es mas amigable usar let en vez de var en un ➿ bucle
//let
const anotherFunction = () => {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i); //Resultado 0-9
    }, 1000);
  }
};

anotherFunction();

//var
const anotherFunction = () => {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i); //Resultado 10 x 10 veces
    }, 1000);
  }
};

anotherFunction();

Este scope solo funciona con let o const, este scope permite su alcance dentro del bloque en el que se instancia ya sea un bucle, un if o un bloque forzado (las llaves puestas solas {} con el único propósito de generar un nuevo scope)
P.D. las variables declaradas en los parámetros de una función o bucle cuentan dentro de estos por ejemplo for(let i = 0; i<10;i++)

Scope bloque
Este scope solo funciona con let o const, este scope permite su alcance dentro del bloque en el que se instancia ya sea un bucle, un if o un bloque forzado (las llaves puestas solas {} con el único propósito de generar un nuevo scope)
P.D. las variables declaradas en los parámetros de una función o bucle cuentan dentro de estos por ejemplo for(let i = 0; i<10;i++)

¿Qué es un bloque en JS?


Mientras llamemos sobre una llave esa variable va estar guardada dentro de un bloque, puede ser una function, un if, for, etc…

Si ejecutamos la siguiente función al ser declaradas con var vamos a poder acceder a los valores de esas variables fuera del bloque, ya que var es una asignación del scope local dentro de la function.

const fruits = () => {
    if (true) {
        var f1 = 'apple'
        var f2 = 'banana'
        var f3 = 'kiwi'
    }

    console.log(f1)
    console.log(f2)
    console.log(f3)
}

fruits();

Pero con let y const no vamos a poder acceder, ya que estos se establecen dentro del bloque.

const fruits = () => {
    if (true) {
        var f1 = 'apple'
        let f2 = 'banana'
        const f3 = 'kiwi'
    }

    console.log(f1)
    console.log(f2)
    console.log(f3)
}

fruits();

Para que funcione el anterior código tiene que ser declarado así:

const fruits = () => {
    if (true) {
        var f1 = 'apple';
        let f2 = 'banana';
        const f3 = 'kiwi';
        console.log(f2)
        console.log(f3)
    }
    console.log(f1)
}

fruits();

También podemos asignar una variable con el mismo nombre y no dar error cuando una esta en el scope global y otra dentro de un bloque

let x = 1
{
    let x = 2
    console.log(x)
}
console.log(x)

Al declarar la variable del for con var y tratar de visualizar el valor de está, veremos que nos muestra el último valor que recorre nuestro for. La solución más simple para esto es asignar la variable let para ese scope de bloque

const anotherFunction = () => {
    for (var i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log(i)
        }, 1000)
    }
}
anotherFunction()

const anotherFunction = () => {
    for (let i = 0; i < 10; i++) {
        setTimeout(() => {
            console.log(i)
        }, 1000)
    }
}
anotherFunction()
const fruits = () => {
    if(true){
        var fruits1 = 'apple';  // scope global
        let fruits2 = 'banana'; // scope de bloque
        const fruits3 = 'kiwi'; // scope de bloque
    }
    console.log(fruits1);
    console.log(fruits2);
    console.log(fruits3);
}

fruits();```

En pocas palabras, la palabra reservada var se debe dejar de usar y solo usar let y const

Confieso que me costo un poco entender porque mostraba 10 vcs 10, así que acá les dejo la explicación

Link de exp

Por si a alguno le interesa, acá les dejo este link de Philip Roberts, el cual hace una de las mejores explicaciones que vi de event loop

const fruit = ()=> {
/*
    Para el scope de bloques debemos de tener en cuenta que si manejamos las variables 
    con la palabra reservada var obtendremos como resultado la referencia a una variable
    local a la funcion (en este caso fruit) pero, si declaramos variables con let
    obtendremos como resultado una referencia a una variable local al bloque, es decir
    terminando el bloque de ejecucion (en este caso el condicional if), la variable deja de existir
*/

    if(true){
        var manzana = "manzana";
        let pera = "pera";
        const guayaba = "guayaba";
    }

    console.log(manzana);
    console.log(pera);
    console.log(guayaba);
}

Para profundizar más sobre este tema les recomiendo este enlace https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/scope%20%26%20closures/ch5.md que hace parte del libro You Don’t Know JS

Cuando declaramos con let y const el scope de la variable es el bloque (no la función), en este caso sólo existen dentro del if.

El scope de bloque esta delimitado por las llaves, por ejemplo, el bloque de código de un if.
Para usar el scope de bloque se debe declarar la variable con let o const, de lo contrario, con var se podrá acceder a la variable en un scope global.
Con var, además de poder acceder a la variable de forma global, también es posible cambiar el valor de forma global. Por ejemplo, si cambiamos el valor de la variable x dentro de un bloque de código, el valor también cambiará fuera del bloque.

Entonces a ver si entendí: con var lo que sucede es que debido al hoisting el interprete eleva a la variable declarada con var, esta queda guardada en el scope global teniendo un mismo entorno léxico y por cada iteración del for el valor se actualiza y cuando el setTimeOut se ejecuta toma el último valor (10).
Y con let lo que está sucediendo es que cada valor que toma “i” es un entorno diferente entonces al ejecutarse el setTimeOut toma el valor en ese momento de la variable “i” que corresponden a distintos momentos del código.
Algo más para agregar? Alguna corrección a lo que escribí?

Para terminar de complementar este modulo del Scope en JS, les recomiendo mucho el video de Sasha en su canal Cocina del codigo, aunque Oscar lo explica bien, tiene pequeñitos errores que puede confundir a un principiante, en su lugar Sasha lo explica de una manera mucho mas didactiva y dinamica, lo cual es mejor visualmente con ejemplos y referencias claras. Les he dejado el video arrriba en el texto, ‘La cocina del codigo’.

Una buena forma de entender el problema del ciclo for, es entendiendo los procesos asincrónicos de Javascript, pásense por el curso de fundamentos de javascript y ahí explican muy bien este tema

¿Cual es la diferencia entre el ámbito léxico y el scope local?

good video

Les dejo el código de la clase.

const fruits = () =>{
    if(true){
        //Cuando declaramos estas variables con var, podemos acceder a ellas
        //fuera del if, dentro del scope de la función
        // var fruits1 = 'apple';
        // var fruits2 = 'banana';
        // var fruits3 = 'kiwi';
        //En cambio cuando las declaramos con let, no podemos acceder a ellas
        //fuera del bloque del if
        let fruits1 = 'apple';
        let fruits2 = 'banana';
        let fruits3 = 'kiwi';
    }
    console.log(fruits1);
    console.log(fruits2);
    console.log(fruits3);
}

fruits();

//Lo que sucede acá es que el console.log dentro de bloque muestra lo que se asigna a la variable que está en el mismo scope.
let x = 1;
{
    let x = 2;
    console.log(x);
}
console.log(x);

//El mismo ejemplo pero cambiando los let por var
//Dentro del bloque de código se reasigna el valor de x, dando como resultado que los dos console.log muestren el último valor asignado de la variable, en este caso 2.
var x = 1;
{
    var x = 2;
    console.log(x);
}
console.log(x);


//Se ejecuta el número 10, esto por razón del hoisting, esto se puede solucionar cambiando var por let.
const anotherFunction =() =>{
    for (var i = 0; 1 < 10; i++){
        setTimeout(() => {
            console.log(i);
        }, 1000);
    }
}

anotherFunction();```

Buen complemento para esta clase:

EL SCOPE en JAVASCRIPT | JS en ESPAÑOL

La verdad prefiero no utilizar var en lo posible.

Var dentro de los bloques de código siempre toma como valor la última declaración hecha.
Mientras que let y const no se reescriben.