Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Loops

9/12
Recursos

Aportes 63

Preguntas 7

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Siempre Let, nunca inLet

Te lo resumo así nomás: En un loop nunca ocupes var, siempre utiliza let para valores que irán cambiando dentro de la ejecución del scope.

Podemos crear Closures de diferentes formas y también de forma involuntaria, esto significa que no tenemos control de lo que estamos creando, tenemos que tener cuidado con nuestras asignaciones o bloques de código que de alguna manera nosotros no controlemos muchas veces sucede porque no establecimos nuestros elementos correctamente.

Con el uso del Scope y los Closures podemos optimizar nuestros proyectos sin ningún problema.

En este video explican que for + let crea un scope para cada iteración del for, es por eso que sí funciona como lo esperamos.

¿Por que copiáis frases que dice el profesor y las pegáis aquí? Para que os den dos puntos?

Scope ( Alcance ) + Closure = Optimizar Proyectos

La respuesta es la sobre escritura que genera al usar VAR y por otro lado LET crea una variable cada vez que se esta recorriendo el loop. Esa es la respuesta

Si no recuerdo mal en el curso de JS con Sacha sucedía un error similar que lo solucionaba en la misma clase, explicando esto mismo!

Básicamente se genera un closure involuntario, el cual es el setTimeout, y que por cada iteración del for hay un nuevo scope. Si usamos var en lugar de let, el valor se va a ir sobrescribiendo durante la iteración, es por eso que obtenemos el valor 10, una vez que los 10 setTimeout se ejecutan.

Algo curioso es que “let” tampoco es muy usado xD La mayoría de las veces vamos a estar usando “const”, ¡Usa const siempre que puedas!

Hola, entiendo por que i toma el valor 10 pero no entiendo por q se imprime 10 veces con ese valor, es decir js ejecuta el for i veces pero por q ejecuta el setTimeout tambien 10 veces… donde se guarda ese conteo si ya i llego a 10???

me hubiese gustado desarrolláramos un proyecto en el curso donde fuésemos aplicando estos conceptos para la solución de un problema en concreto para los que estamos empezando afianzáramos de mejor manera estas herramientas.

Hola, con todo respeto al profesor.
Creo que habla mucho demás y no permite que uno se concentre en los términos que en verdad valen la pena.

Los Loops son como un tipo de closure, que si los usamos de forma correcta, nos permite generar un scope local de tipo bloque, para poder recordar el alcance o ámbito léxico en donde se debe ejecutar y poder acceder a la variable, recordando su valor.

BIEN

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

another()
//R: 0, 1, 2, 3, ... , 9

MAL

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

another()
//R: 10, 10, 10, 10, ... , 10

Si se le quita el setTimeout funciona con var, lo que pasa es que al tener el setTimeout cuando hace la pausa la hace despues de ejecutar todo el codigo entonces al momento de imprimir ya en var es 10. cuando es let no me queda claro el por que si muestra cada valor.

const loop_test = () =>{
    for (var i = 0; i < 10; i++) {
        console.log(i);    
    }
}
loop_test();

Si no entendistes como yo… usa Let y no Var.

Closures

Loops : Al crear ciclos iterativos se crean closures por lo que tenemos que tener cuidado al momento de declarar nuestras variables porque se puede perder control de lo creado y los resultados no serán los esperados.

// Loops

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

anotherFunction();

Repositorio 🐙

USA CONST !!!

si por alguna razón como en los “ciclo for” debes cambiar valores, usar LET

A VAR ni lo mencionemos

Encontré que este loop, se puede escribir con var de esta forma:

// loops
const anotherFunction = () => {
    for(var i = 0; i < 10; i++) {
        (function(n){
            setTimeout(() => console.log(n), 500)
        })(i)
    }
}

anotherFunction()
// 0, 1, 2, 3.....

pero igual creo que es mejor usar con let 😅.

Yo sabía ese code snippet debía tener mayor explicación!, y aún así mi conclusión sigue siendo la misma (a ver, repite conmigo):
“Usar siempre let, nunca var” 🤪

El keyword var ya no debería usarse para definir variables, se hace más complejo tener una referencia y scope claro de la misma

En el curso de Sacha, se habal un poco de los tipos de variables a usar, y recuerdo que para valores iterables se usa let - para valores reescribibles se usa var - y para constantes fijas se usa const 👏

JS solo puede hacer una cosa a la vez, si hay múltiples tareas (como funciones), estas serán recolectadas, ordenadas y puestas en cola, una vez se tengan todas las tareas en cola, se comenzarán a ejecutar en orden.
.
var no limita el alcance (o tiempo) en que pueden ser accedidas las variables, si una función en cola debe acceder a una variable var, sólo accederá a ella en el estado que se encuentre al final del proceso de recolección.
.
En este caso todas las tareas (funciones setTimeout) terminan de ser recolectadas cuando la variable var ha llegado a su última iteración; Al haber iterado 10 veces, se alinean en cola 10 órdenes de imprimir la variable i, y como var = 10 al momento de ejecutarse las impresiones, las 10 órdenes imprimirán el número 10.
.
Usando let en lugar de var podemos resolver este problema ya que ahora al estar limitado el alcance, setTimeout solo tendrá acceso a la variable en la iteracion exacta que ordena ejecutarlo (1,2,3,4…), y cada console.log(i) en cola solo imprimiría el valor de i al que tuvo acceso durante su recolección.
.
Gracias por venir a mi TED Talk.

Les comparto una anecdota reciente (hace 30 sg)
Acabo de resolver un problema que se nos presento en la empresa:

Contexto -> agregar una lista de productos al carrito del usuario, uno despues del otro. Necesitabamos hacerlo de manera asincrona.

Problema -> decidi agregar los productos recorriendo el array atravez de un for…in de la siguiente manera:

for(index in _PRODUCTOS) {
    // simulacion de petición ajax
    setTimeout(function(){
        console.log(index)  // imprimirá el producto actual despues de 5sg, uno tras otro.
    }, 5000)
}

El problema de esto es que si no se declara index con let o const, esta será declara como una variable global var, así:

for(var index in _PRODUCTOS) {
    ...
}

Esto ocasionaba que solo se agregara al carrito el ultimo producto ya que esta variable index cambiaba su valor tras cada iteración SIN TENER EN CUENTA EL TIEMPO QUE DEMORA LA PETICION AJAX

Solución -> Declarar la variable index con let, asi:

for(let index in _PRODUCTOS) {
…
}

Ahora index es una variable unica del bloque donde se esta ejecutando y no cambia el valor ya que en la siguiente iteración index será una variable totalmente distinta a la de la iteración anterior.

var no es un problema, tiene sus casos de uso, esto es darwiniano si algo no funciona es sacado, por algo ECMAScript no ha removido esto, solo que no entendemos este tipo de cosas y tendemos a hacer malas practicas y puede pasar hasta en un lenguaje fuertemente tipado.

Aunque… si declaro la variable let por fuera del for obtendremos el mismo comportamiento que con var. Este es un sencillo ejemplo para demostrar cómo funciona el hoisting, que es literal inicializar las variables desde el principio del contexto de ejecución, por lo que al declarar antes la variable emulamos este comportamiento! 😱

function functionName() {
	let i;
	for(i = 0; i < 10; i++) {
		setTimeout(function() {
			console.log(i);
		}, 1000);
	}
}
functionName();

En un loop la variable i no debe declararse con var, ya que sus valores irán cambiando en cada loop, por esta razón se debe declarar como let.

Les recomiendo complementar éste curso con el curso profesional de Javascript, donde nos enseñan cono funciona el satck, schedule task y task queue. Lo cual es muy importante para saber que pasa con el setTimeout que esta dentro del ciclo for.

Podemos crear Closures de formas involuntarias, que puede ser un error ya que nosotros no lo estamos controlando y obtendremos valores particulares.

Como en el caso de Scoope Block donde se generaba un error donde siempre nos apareciera un 10 al momento de tener var ahi es donde se estaba generando un Closure, Pero lo pudimos solucionar cambiando el var por let, para poder recordarle ese scope de bloque. Hay que tener cuidado de la forma que no podamos controlar este tipo de problemas.

Let nos da un scope en code block y asi podemos manejarlo en este bloque de codigo

Mil disculpas, pero yo no le entiendo al profesor.

Gracias comunidad, sin sus aportes hubiera demorado mucho más en comprender estos conceptos

Entendido!!

// The global setTimeout() method sets a timer which executes a function or specified piece of code once the timer expires.

// setTimeout() is an asynchronous function, meaning that the timer function will not pause execution of other functions in the functions stack. In other words, you cannot use setTimeout() to create a "pause" before the next function in the function stack fires.

//con var (global scope) ejecuta el loop, ‘i’ llega a su valor máximo, cuando el timer expira imprime el valor límite de i. Con este código muestra 01234 y 55555

//con let (block scope) y este código muestra 01234 y 01234

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

};

anotherFunction();

Te lo resumo así nomás: En un loop nunca ocupes var, siempre utiliza let para valores que irán cambiando dentro de la ejecución del scope.

debemos usar let y const, si podemos evitar el Var

Había leído mucho sobre el var vs. let en JS, ahora comprendo mejor porqué de usar let y const en lugar de var. He revisado código de terceros y hasta el momento no veo mucho el uso de var.

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

Loops: Podemos crear closures de distintas formas y también de forma involuntaria, esto significa que no lo estamos controlando. Aquí un ejemplo de una de las clases anteriores para explicarlo mejor:

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

El closure en este caso viene siendo el setTimeout() y como el Profe Oscar mostró si usas var, en el setTimeout() por consola se te mostrará 10 veces el número 10, ya que el setTimeout es asíncrono y va a ejecutarse luego de haber recorrido todo el for. Y tendrá el valor de 10, debido a que var tiene un function scope debido al hoisting. Si el console.log estuviera afuera funciona normal porque es código síncrono es decir que va paso a paso. El verdadero problema del var es que se ve afectado por el hoisting. Por lo tanto la computadora leería el código así:

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

La solución para esto sería que a la hora de crear loops(ciclos o bucles) utilicemos let debido a que let no se ve afectado por el hoisting.

Ejemplo practico de closure en un loop

HTML

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Closure en loop</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            font-family: Arial, Helvetica, sans-serif;
            font-size: 12px;
        }
        
        .form-container {
            width: 80%;
            height: 300px;
            background-color: cadetblue;
        }
        
        form {
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        
        input {
            width: 100px;
        }
    </style>
</head>

<body>
    <div class="form-container">
        <form action="">
            <p id="help">Mensaje de ayuda aquí</p>
            <label for="correo">Correo</label>
            <input type="email" id="correo" name="correo" />
            <label for="nombre">Nombre</label>
            <input type="text" id="nombre" name="nombre" />
            <label for="edad">Edad</label>
            <input type="number" id="edad" name="edad" />
        </form>
    </div>
    <script src="./index.js"></script>
</body>

</html>

JavaScrpt

const showHelp = (help) => {
    document.getElementById("help").innerHTML = help;
};

const setupHelp = () => {
    var helpText = [
        { id: "correo", help: "Direccón de correo electronico" },
        { id: "nombre", help: "Nombre completo" },
        { id: "edad", help: "Edad (debes tener más de 16 años)" },
    ];
//Solo reemplaza var por let o const
    for (var item of helpText) {
        document.getElementById(item.id).addEventListener("focus", () => {
            showHelp(item.help);
        });
    }
};
setupHelp();

Loops

const anotherFunction = () => {
  for(var i = 0; i < 10; i++) { //Para hacer loops no se debe usar var
    setTimeout(() => {
      console.log(i)
    }, 1000)
  }
}

anotherFunction() // 10, 10, 10, 10, 10, 10, 10, 10, 10, 10

Muchas veces podemos hacer closures de forma involuntaria que no permiten que nuestro código funcione de la forma en que queremos, por lo tanto hay que estar pendientes de manejar las variables de forma correcta, debido a que en ocaciones puede perjudicar el rendimiento de nuestras aplicaciones al momento de contruirlas.

const anotherFunction = () => {
  for(let i = 0; i < 10; i++) { // debemos usar let debido a que este sirve 
	//para tener un alcance más limitado y no ser global como var
   setTimeout(() => {
      console.log(i)
    }, 1000)
  }
}

anotherFunction() // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Si estas en un lopp siempre let si los valores cambiaran a futuro

return 

Tuve curiosidad por saber cómo resolver el loop sin usar let.

  1. Immediately invoked function expression (IIFE)
const solutionIife = ()=>{

	for(var i = 0; i < 10; i++){
  //asignamos i a idx para que visualmente sea entendible.
 
   (function(idx){ 
   // idx es  lo que le pasamos a  la IIFE, ahora está en el scope de esta funcion
   console.log(idx + " idx INVOKED"); 
   setTimeout(()=>{
   //Tiene acceso a idx
    	 console.log(idx + " scope setTimout" );
    },1000)
   })(i); // Aquí pasamos i a la IIFE
  }
};

  1. Declarar funcion de manera externa y e invocarla dentro del setTimeout. Funciona básicamente como la anterior fn, pero declaramos una función externa que será invocada en setTiemout.

function printRes(idx){
  return console.log(idx);
}

const outsideFnSolution=()=>{
	for(var i = 0; i < 10; i++) {
    setTimeout(printRes(i),1000)
  }
}

Gracias a este video terminé de entender por que el setTimeout muestra siempre el mismo valor

ahora el var me huele a mal, como que no lo utilizaré en mis códigos solo en caso extremos.

f

Entendido!

Demasiado interesante, este es un buen ejemplo para aprender definitivamente la diferencia entre los alcances que tiene var y let

Creando closures en loops: Un error común
Antes de la introducción de la palabra clave let en JavaScript 1.7, un problema común con closures ocurría cuando se creaban dentro de un bucle ‘loop’.
By: https://developer.mozilla.org/es/docs/Web/JavaScript/Closures

Let, let, let.

Definitivamente se debe usar let o const, para estar seguros de lo que pasa,

Excelente clase, muy bien explicado!

de donde viene el valor 10 que devuelve el VAR i = 0; ???

les dejo estos recursos si quieren aprender más de los clousures
https://www.youtube.com/watch?v=E6aPTeVujRs
https://www.youtube.com/watch?v=yXRf98SN1P4

Tengo que admitir que había sobre estimado el curso este y me llevo una grata sorpresa

Para este ejemplo lo importarte a notar es que cuando usamos let en un loop este valor no puede ser reasignado como si usáramos var, resultando para el proceso asíncrono una variable con valor independiente a mostrar ya que genera un nuevo scope local de forma interna para cada ciclo (se podría decir que funciona como un closure interno).

Siento que el scope y los closures son dos caras de la misma moneda

Se tiene que tener mucho cuidado en el manejo de la variables, lo recomendable es utilizar let en las estructuras repetitivas, para así evitar de crear closures involuntariamente, el cual no cumple la función deseada.

Adios var, gracias por todo.

En resumen, poner atención al Scope al declarar nuestras variables, verdad? Buscando siempre tener el control sobre nuestro código.

Estoy en lo cierto? Yo entendí eso, gracias a quien me corrija o me confirme!