Los loops son una de las cosas más útiles y necesarias en cualquier lenguaje de programación. Sirven para repetir una tarea un determinado número de veces. Así, podemos recorrer todos los elementos de una array con un loop for, etc.

Yo me voy a centrar en el loop for porque es el más usado y más útil, pero hay otros muchos: for..in, do..while, while, etc.

El loop for

El loop for tiene la siguiente sintaxis:

for( [variables]; [condiciones]; [variación] ){
	//código
}

En cada iteración, la variable toma un valor determinado por el incremento… Por ejemplo:

for(var i = 0; i <= 10; i++){
	window.console && console.log(i)
}

Si ejecutáis esto en la consola (ver parte 1 de esta serie), os saldrán valores del 1 al 10. Si no se os ha ocurrido, se puede usar para recorrer una array:

var miArray = ["valor1", "valor2", "valor3", "valor4", "valor5"];
//Recordad que array.length devuelve el número de ítems de la array
// i++ se usa para aumentar el valor de la variable
for( var i = 0; i < miArray.length; i++ ){
	console.log(miArray[i])
}

Así, os saldrían los valores de cada elemento de la array.

Consideraciones

En loops cortos, no importa demasiado en cuanto al rendimiento acceder a la longitud de la array una vez cada iteración, pero en loops largos en los que la array no cambie deberíamos “cachear” la longitud. En el siguiente ejemplo cachearíamos la longitud en una variable llamada len:

for(var i = 0, len = miArray.length; i < len; i++){
	// Super código con mi array
}

Con lo que sabemos…

Si has leído y entendido las anteriores entradas de esta serie, ahora mismo serías capaz de mostrar las entradas de un feed de blogger, que usa JSON:

function mostrarEntradas(json) {
	// Ésta función será el callback de nuestro script, y nos retornará un objeto Json, con una estructura determinada.
	var divContenedor = document.getElementById('contenedor-entradas'),
		entradas = json.feed.entry, // Aquí obtenemos la array con las entradas
		html = '', // Aquí almacenaremos el HTML
		num = entradas.length, // Cacheamos la longitud
		i = 0, // Creamos la variable (para ahorrar espacio)
		entradaActual; // Aquí almacenaremos la entrada en cada iteración del loop
	// El loop
	// lo mismo que for(var i = 0, num = entradas.length; i++)
	for(; i < num ; i++){
		entradaActual = entradas[i]; // Seleccionamos la entrada actual
		html += '<h5>' + entradaActual.title.$t + '</h5>';
		html += '<p class="fecha">' + entradaActual.published.$t + '</p>';
		html += '<p class="autor">Por ' + entradaActual.author[0].name.$t + '</p>';
		html += '<p>' + (entradaActual.summary || entradaActual.content ).$t + '</p>';
		// Omito el link porque hay que hacer otro loop más
	}
	// mostramos el resultado
	divContenedor.innerHTML = html;
}

Obviamente se puede complicar mucho más la cosa (link, imágenes, etc), pero lo básico estaría hecho. Para ejecutarlo sólo habría que poner algo como:

<div id="contenedor-entradas"></div>
<script src="http://urldetublog.blogspot.com/feeds/posts/summary?alt=json-in-script&callback=mostrarEntradas"></script>

He hecho un ejemplo para mostrar el blog que vosotros queráis:



8 pensamientos en “Básicos de Javascript [5]: El loop for

  1. Bitacoras.com
  2. Imagen de DuncanDuncan el dijo:

    Sobre lo de el cache al length del array, es bueno decir que ya los navegadores modernos son lo suficientemente inteligentes para cachearlos por ellos mismos, asi que si no lo cacheamos nuestro código correrá tan rápido que como si lo hubieramos hecho, este truco o tip era de uso obligatorio en el pasado, pero ya se ha quedado algo obsoleto, aunque aun es util en versiones muy antiguas de los navegadores, saludos.

    • Imagen de Emilio Cobos Álvarez el dijo:

      Sí, en los navegadores modernos de escritorio se optimiza el loop independientemente de si se usa o no, pero en los móviles esa optimización no está igual de bien realizada.

      No obstante, también es importante para no obtener resultados no deseados en loops donde la array / colección puede variar, como una NodeList, o similar. Me refiero, imagínate que a todos los <span> le quieres añadir un icono, realizado con una etiqueta span, si haces esto:

      var spans = document.getElementsByTagName('span'),
       	i = 0,
      	icon;
      for(; i < spans.length; i++)  {
      	icon = document.createElement('span');
      	icon.className = 'icon-cualquiera';
      	spans[i].appendChild(icon);
      }

      Estarías haciendo un loop infinito, que no pasa si cacheas la longitud.

  3. Imagen de DuncanDuncan el dijo:

    En que te basas para decir que en los navegadores móviles esa función no esta bien optimizada? si los navegadores móviles utilizan el mismo engine de javascript en su versión mobile que en la de escritorio, por ejemplo chrome utiliza el v8 en su versión de android y firefox utiliza IonMonkey en su versión mobile y safari igual usa nitro para IOS, quizas con algun evento adicional, pero en esencia son el mismo, y sobre el ejemplo de código que colocaste me parece que es un caso “muy especifico” y que como mencionaste se solventa cacheando el .length o tambien usando querySelectorAll en vez de getElementsByTagName (aunque con una pequeña perdida en rendimiento), ya que este devuelve un nodeList estatico. En fin si quieres una micro optimización sigue cacheando el .length, pero toma en cuenta que la mejora en rendimiento actualmente es tan insignificante que ya no vale la pena, y ademas hace que el codigo se menos legible (para los programadores recien iniciados), Saludos.

  4. Imagen de DuncanDuncan el dijo:

    Por ese mismo test era que te lo decia, ya lo habia visto con anterioridad, la diferencia es muy mínima, en promedio un 10 -12% en FF, Chrome y safari, en opera e iE va por el 33%, que en operaciones básicas de javascript que son tan rápidas, hablamos de pocas milesimas de segundos de diferencia en mas de un millon de iteraciones, y que en un “escenario real” es muy poco probable que hagamos tantas iteraciones, y aun asi repito, son pocas milesimas de segundo. Por su puesto, no deja de ser una buena practica… obsoleta, quizas en video juegos aplique, pero por ejemplo un escenario bueno y que aumenta en mucho el rendimiento es usar DocumentFragment al insertar elementos nuevos en el dom, o cachear un elemento del dom hacerle modificaciones y luego remplazarlo por el original, cosas asi son buenas practicas, porque la mejora de rendimiento se puede apreciar, ya que elimina los repaints y reflows, que esos si que son costosos. En fin, y si me parece que afecte la legibilidad y tambien la elegancia.

    • Imagen de Emilio Cobos Álvarez el dijo:

      Como bien dices, depende mucho de lo rápida o lenta que sea la operación. Para navegar por una lista de strings y hacer alguna modificación, pues no tiene mucho sentido, pero a la hora de filtrar una gran cantidad de elementos para ver si coinciden con un selector, o hacer interacciones rápidas con el usuario, esos milisegundos pueden ser vitales.

      Échale un vistazo a Masonry. Imagina el costo de iterar sobre 100 elementos cada vez que la ventana cambia de tamaño. Sin esas pequeñas microoptimizaciones a la hora de hacer el loop podría resultar incluso más pesado (lo digo porque lo he probado recientemente en android 2.3, y ya de por sí consume bastante).

      Esto no está lejos de un “escenario real”, y un porcentaje de un de entre el 10 y el 33% de operaciones por segundo es un porcentaje muy a tener en cuenta.

      A mí me parece más legible sin caché, pero mucho más elegante con ella :P

  5. Imagen de DuncanDuncan el dijo:

    “Imagina el costo de iterar sobre 100 elementos” las iteraciones en javascript son operaciones de las mas básicas, son demasiado rápidas y muy ligeras, hacer 100 iteraciones en un loop es hablar de nanosegudos, el 10-30% de nanosegundos no es un porcentaje a tener en cuenta. Y como bien lo has escrito, es una “micro-optimización”, anteriormente el .length de un array era un campo calculado, que cada vez que iterabas se tenia que volver a calcular, y las diferencias en rendimiento si eran grandes, pero ya esto no es asi, ya los navegadores la cachean, puedes por ejemplo revisar el codigo fuente de webkit y verlo tu mismo, el archivo creo que se llama DynamicNodeList.cpp. La cuestion es que esta micro-optimizacion quizas sea necesaria en algunas cosas muy muy puntuales, pero no deberia ser la regla en el código como piensan muchos.
    Te pongo un ejemplo en C#, que es un lenguaje manejado, tambien trae la opción de escribir código no manejado(con punteros), se sabe que esto mejora el rendimiento “dramaticamente”, que es una verdadera optimización, pero en el dia a dia, lo programadores .net solo lo usan para partes muy criticas del código, donde la optimización es mas que necesaria, no lo usan como regla en todo su código, otro ejemplo que te puse arriba el querySelectorAll vs getElementsByTagName, aqui la diferencia de rendimiento es hasta de mas de 100%, para muchos puede parecer una cifra escandalosa, pero como son operaciones muy básicas y veloces, en el dia a dia ese 100% de diferencia no tiene ningun peso.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Puedes usar las siguientes etiquetas y atributos HTML:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre data-language=""> <ul> <ol> <li>
Para poner código usa <pre data-language="[lenguaje]"><code>[código]</code></pre>, y no olvides escapar el HTMl.