Una sinfonía en C#

Un pequeño aporte a la comunidad de habla hispana.

Predicados y array en Javascript: find, filter, some.

En esta tercera parte vamos a ver varios métodos juntos, find, filter y some porque...bueno, porque sí.
En realidad porque tiene algo en común, todos reciben como parámetro un predicado

¿Y qué es un predicado?

En este contexto es una función que establece una condición contra la cual se evaluarán elementos.
Dicho en palabras un poco menos complicadas, pasamos una función que será la encargada de decirnos si un elemento de un array cumple con una condición.
Veamos un ejemplo:

Array.filter

Empecemos con filter, al final los tres métodos son similares pero hacen cosas distintas.
Filter permite tomar solo aquellos elementos de un array que cumplen con una condición, en este caso, determinada por el predicado.
Entonces, si tenemos el siguiente array:

var a = [1,2,3,4,5,6,7,8,9];

y quisiera quedarme solo con aquellos elementos que son pares podría hacer esto:

var aa = [];
for(var item in a){
     if(item % 2 == 0)
         aa.push(item);
}
console.log(aa);

Con filter la cosa sería así:

aa = a.filter(function(item){
     return item % 2 == 0; });

El resultado es exactamente el mismo.

Y es igual que:

aa = a.filter((item)=> item % 2 == 0);

Aún más elegante.

Algunas características de filter:

  • Solo se invoca el callback (el predicado) para elementos que tiene valores, es decir, los elementos del array sin valores se ignoran.
  • Los elementos borrados durante la ejecución no son visitados.
  • El rango de elementos a visitar se establece antes del inicio de la iteración, es decir, si se agregan elementos los mismo no son visitados.
  • Si un elemento cambia de valor se leerá el nuevo valor.

Además filter recibe dos parámentros, el callback que recibe tres: el elemento actual, el índice actual y el array original.
El segundo parámetro es el contexto de this, vamos, igual que las funciones que vimos en los posts anteriores.

Todo es es igual para el caso de find y some, veamos cómo funcionan.

Find

Simplemente retorna el primer elemento que coincida con el criterio del predicado, en el ejemplo anterior retornaría el número 2.

a.find((item)=> item % 2 == 0);

Evidentemente si hay más elementos que cumplen la condición establecida en el predicado son ignorados, en caso de no haber ninguno retorna undefined.

a.find((item) => item > 10);

Las mismas reglas de comportamiento anteriores se aplican a find.

Some

En este caso devuelve true si al menos un elemento cumple con el criterio de búsqueda y false si no hay ninguno.

a.some((item) => item > 2);

Devolverá true.

a.some((item)=> item > 10);

Devolverá false, sería casi como hacer algo así con find:

a.find((item)=>item > 10) != undefined;

Lo dejamos acá por hoy, nos leemos.

Array map en Javascript, se usa mal?

En el post anterior hablamos sobre Array.forEach y su funcionamiento, ahora vamos con el que hoy en día (creo yo) es el segundo método de Array más usado, map.

Map recorre un array y crea un nuevo array como resultado de la invocación a una función dada.
En palabras simples, map recorre un array y aplica una función (que es parámetro) a cada elemento del mismo, y crea un nuevo array con los elementos resultantes.

Un ejemplo simple (y no muy útil)

var a = [1, 2, 3, 4];
const m = a.map(function(item){
     return item;
});
console.log(m);

O lo que sería lo mismo:

m = array1.map(x => x);

Lo que ocurre es que la función que se pasa como parámetro es quien genera el resultado, en este caso devuelve el mismo elemento que recibe (en item se pasa cada valor del array, uno a la vez) entonces el resultado es igual, pero es un nuevo array, no es el mismo.

Evidentemente este ejemplo no tiene mucha utilidad, en genera uno realiza operaciones dentro de la función, por ejemplo:

var a = [1, 2, 3, 4];
var m = a.map(function(item){
     return item * 2;
});
console.log(m);

En este caso la función recibe en item cada elemento y retorna su valor * 2.
Por supuesto que dentro de esta función podemos hacer cualquier cosa, incluso ignorando los valores del array original.

var a = [1, 2, 3, 4];
var m = a.map(function(item){
     console.log(+new Date());
});

Alguna características de map:

  • La función recibe tres parámetros, el item actual, el índice del elemento y el array orginal, con lo cual podemos operar sobre el array orginal.
  • Se invoca a la función una vez por cada elemento del array que contiene valores.
  • Si no se usa el array resultante o no se retorna un valor en el callback se considera incorrecto el uso de map, en tal caso se puede usar for-of o forEach.
  • Los elementos recorridos por map son determinados antes de iniciar el recorrido.
  • Los elementos que hayan cambiando luego de iniciada la iteración se considerará su valor actual.
  • Los elementos removidos no son recorridos (ya que sus valores serían inválidos).
  • Es posible pasar el contexto como segundo parámetro (que tomaría el valor de this).

Como vemos muchas de estas características son iguales a forEach.

Entonces, cuándo usamos map y cuándo forEach?

Como dice más arriba, si no vamos a utilizar el array resultante se considera un antipatrón usar map y debemos echar manos de forEach o for-of.

El uso tal vez más común al consultar una API sería "reformatear" los objetos obtenidos.

var a = [{"nombre":"Marcelo", "nombre":"Leonardo"}];
var m = a.map(function(item){
     return {"Nombre":item.nombre}
});

console.log(m);

Nos leemos.

Métodos para trabajar con Arrays en Javascript

Esto viene de la curiosidad que me dio ver que varias personas utilizan el método map de Array para iterar aunque no deseen mapear los objetos, al preguntar el porqué de tal decisión me he dado cuenta que hay varios métodos del objeto Array poco conocidos que son muy útiles y, en algunas ocasiones, más adecuados según el caso de uso.

Los arrays en Javascript son cosa de todos los días, cuando manipulamos datos gran parte de las veces se trata de un array de elementos. Entonces conocer algunos métodos relacionados con ellos nos puede ser útil.
En este caso vamos a repasar algunos que me parece más útiles.

A los largo de algunos posts veremos:

  • Array.prototype.forEach
  • Array.prototype.map
  • Array.prototype.some
  • Array.prototype.filter
  • Array.prototype.find
  • Array.prototype.reduce
  • Array.prototype.findIndex

No todos separados, dependiendo un poco de lo largo que vayan quedando los posts.

Array.prototype.forEach

Empezamos con el que creo será el más común que utilizar al consultar un servicio.
forEach permite iterar todos los elementos de un array. Algo así:

var a = ['a', 'b', 'c'];
a.forEach(item => {
   console.log(item); });

Entonces en lugar de iterar con un for clásico (clásico para los que estudiamos programación estructurada) con forEach se recorre todo el array y nos da una referencia en el parámetro item.

Algunas características del forEach:

  • La cantidad de elementos a recorrer es establecida antes de iniciar el bucle, por lo tanto si agregamos un elemento dentro del forEach el mismo no será visitado.
  • Siempre retorna undefined, por lo tanto no es posible encadenarlo
  • No es posible interrumpir su ejecución (excepto con una excepción)
  • Si un elemento cambia y forEach no ha pasado aún por él se leerá el valor actualizado.
  • Si un elemento no visitado es borrado no será visitado.
  • Si un elemento ya visitado es borrado el resto de los elementos no será visitado.

El callback que recibe forEach como parámetro recibe 3 argumentos

  • El elemento actual que se está visitando.
  • El índice del elemento actual.
  • Otro array.

This dentro del forEach.


El valor de this dentro del forEach es el contexto actual (window en el navegador), es posible pasar un segundo parámetro a forEach a modo de contexto.

function Counter() {
   this.sum = 0;
}
Counter.prototype.add = function(array) {
   array.forEach((entry)=>{
     this.sum += entry;
   }, this);
};

Si hacemos:

var c = new Counter();
c.add({1,2,3});

el resultado es la suma, ya que el acumulador de this es el miembro sum del objeto Counter.

Y para qué es el tercer parámetro? un array?

El tercer parámetro que recibe el callback es el array original, ya que en Javascript los parámetros se pasan por valor (es decir, son copias) si hacemos esto:

var a = [1,2,3];
a.forEach(function(item, index, aa){
     item = 0;
});

Si comprobamos el valor del array a vemos que los valores no cambiaron, si quisiéramos cambiarlos deberíamos operar sobre el tercer parámetro que es el orginal.

a.forEach(function(item, index, aa){
     aa[index] = 0;
});

al comprobar el valor del array original vemos que todos sus valores fueron sobre-escritos, mágico.

Bueno, lo dejó acá. Espero les sea útil. Nos leemos.

Los memes de Javascript

No pasan más de 10 minutos desde que algo ocurre en el mundo hasta que Internet se llena de memes al respecto; sin embargo últimamente se ven muchos memes sobre Javascript y la idea de este post es explicarlos, o mejor dicho, explicar por qué son incorrectos.

El meme en cuestión

En meme del que voy a hablar en esta ocasión es éste, con Patrick Star de protagonista:

 

image

 

En este caso es una burla acerca de ciertos casos con las comparaciones en Javascript, y si bien tiene algo de gracia demuestra más que nada desconocimiento del lenguaje y vamos a explicarlo.

El comparador de igualdad

El comparador de igualdad de Javascript tiene una característica interesante que se podría resumir como que “hace el mejor esfuerzo por comparar los dos términos” para explicarlo simple: el comparador convierte los dos término en caso de no ser del mismo tipo y luego hace una comparación estricta, entonces esto nos lleva a la primera parte del meme:

0 == “0”

Básicamente al usar el comparador de igualdad == Javascript detecta que los términos no son del mismo tipo y los convierte, entonces esta comparación pasa a ser verdad como podemos ver al probarlo en Nodejs

image

es por eso que si queremos una comparación estricta usamos el operador de comparación estricta ===

image

Entonces, primer caso resulto, Javascript hace exactamente lo que dice la documentación que debe hacer, una comparación con conversión de tipos.

Un array vacío

Los arrays siempre tienen sus bemoles en todos los lenguajes y Javascript no es la excepción, pero por qué  0 == [ ] ?

La respuesta es que la conversión de un array vacío a entero nos retorna el valor de una posición de memoria vacía que es comparable con 0, entonces la comparación es verdadera, una vez más si usamos el comparador estricto es no es así:

image

La comparación con un string es false

 

"0" == [] 

Acá es simple, basados en lo anterior, es evidente que podemos convertir un array vacío a entero y nos retorna algo comprable con false porque después de todo estamos pidiendo que haga un esfuerzo por convertir una posición sin valores. En este caso el término de la derecha resultará ser o o algo comparable con false, sin embargo ahora el término de la izquierda es un string que a lo sumo es comparable con un 0.

Conclusión

Un lenguaje de programación es complejo y tiene detalles, si en el día a día lo usamos debemos conocer sus características y no olvidarnos que puede ser (como en el caso de Javascript) un lenguaje diseñado hace muchos años y si estamos acostumbrados a lenguajes más modernos que han aprendido de los problemas que pueden acarrear estas cosas y que los programadores de hoy en día usan un lenguaje sin conocerlo…

 

Nos leemos.