Seleccionar página

Matriz, arreglo o Array -que de todas estas formas los conocemos- es una poderosa herramienta, junto con los objetos, para la gestión de datos en Javascript. En las distintas versiones de ECMAScript se han ido incorporando nuevos métodos y funcionalidades para hacer más sencillo el manejo de Array.

El problema surge a la hora de comprender su comportamiento, ya que las diferentes oleadas de funcionalidades han seguido -desde nuestra humilde perspectiva- criterios no siempre homogéneos, por lo que nos encontramos con métodos que modifican la matriz, otros que no la modifican y devuelven una nueva matriz, otros que ignoran los valores no definidos de las matrices dispersas y otros que sí los gestionan. Es un cierto galimatías, por lo que, para intentar dar algo de luz sobre el tema, vamos a dar un repaso a las distintas formas que nos ofrece Javascript para el trabajo con matrices, indicando en cada caso desde cuando están disponibles y analizando sus patrones de funcionamiento.

Advertencia: este es un artículo largo. Si no tienes paciencia para leerlo entero, quizás te interese ver simplemente las conclusiones que aparecen al final.

Crear un Array

Hay tres formas principales para crear una matriz, aunque algunos otros métodos pueden devolver una matriz desde otros tipos datos. Básicamente podemos crearla con:

Expresión literal []

Es la forma más habitual y simplemente debemos utilizar los corchetes y poner los valores separados por comas.

var matriz = [1, 2, 3];

Si queremos crear una matriz dispersa, es decir, sin definir alguno de sus valores, simplemente no indicamos el valor y seguimos con la siguiente coma.

var dispersa = [1, , 3];

Bueno, este caso tiene una situación especial, ya que, si los valores no definidos queremos ponerlos al final de la matriz, entonces hay que poner una coma adicional a lo que cabría de esperar.

var dispersa = [1, 2, , , ];
console.log(dispersa.length); // 5

Este comportamiento resulta bastante extraño. Afortunadamente no se suele crear una matriz dispersa desde una expresión literal, pero si quisiéramos hacerlo, fácilmente nos desconcertaría el tener que poner una coma de más si los elementos definidos los queremos situar al final de la matriz.

Constructor new Array()

Este constructor o función (se puede invocar con o sin new) permite crear una matriz indicando su tamaño pasando un solo parámetro con un número entero. Esta matriz tiene el tamaño indicado, pero no tiene ningún valor declarado por lo que es una matriz dispersa.

var vacia = new Array(10);

Lo que puede resultar confuso es que si pasamos más de un valor entonces se crea una matriz con los valores pasados como parámetros.

var matriz = new Array(1, 2, 3);

Lo que no podemos hacer es crear una matriz con un valor de un solo valor entero, ya que interpreta que queremos indicar un tamaño. Este comportamiento es fuente de confusiones y errores.

Método estático Array.of()

Para corregir el problema de la interpretación de los parámetros de constructor new Array() se ha creado en ES6 Array.of(). Este nuevo método estático interpreta todos los valores pasados como parámetros como el contenido que queremos incluir como valores del Array. De esta forma Array.of(10) crea un Array con un solo valor de tipo entero.

var matriz = Array.of(10);

Con el constructor pasando varios valores o con Array.of() no es posible crear una matriz dispersa, ya que si omitimos un parámetro obtendremos un error. Si pasamos undefined como parámetro no estamos creando una matriz dispersa, ya que el valor ha sido definido con valor undefined.

Nota: Es bastante difícil de comprender que una matriz dispersa es una matriz que algunos o todos sus valores no han sido nunca definidos, pero si alguno de sus elementos ha sido explícitamente asignado a undefined ese valor se considera como definido y no estamos ante una matriz dispersa.

Novedades

Comparación estricta y no estricta en Javascript

Aunque pueda parecer que comparar dos valores es algo sencillo y común, lo cierto es que comparar en Javascript conlleva algunas dificultades que debemos conocer, en especial la diferencia entre la comparación estricta y no estricta, es decir, la diferencia entre == (con sólo dos signos de igualdad) y === (con sólo tres signos de igualdad).

Sistema de pruebas minimalista en Javascript

En todos los navegadores modernos y en Node disponemos de console.assert() para comprobar el resultado de nuestras funciones y construir un sencillo conjunto de pruebas sin necesidad de instalar absolutamente nada. Es un sistema minimalista, sin dependencias y que funciona muy bien. Os animamos a conocer un poco más de esta pequeña herramienta.

Esquema de módulo Javascript para navegador y Node

Una de los requisitos cada día más común es que nuestro código debe poder funcionar sin problemas tanto en el navegador como en el servidor con Node. Esto puede parecer en principio algo sencillo, pero debemos tener en cuenta algunas características de cada uno de los entornos para construir un módulo que pueda funcionar correctamente en ambos contextos.

Progressive Web Apps – Jad Joubran

The web is becoming more and more powerful everyday, especially with the launch of Progressive Web Apps. PWAs are experiences that combine the best of the web and the best of apps. You can now build web apps that run from your home screen, receive push notifications & work offline.

breves

Descrubir algunas características de console

En el día a día nos encontramos muy a menudo utilizando console. Es una navaja multiusos que nos facilita la vida a la hora de depurar nuestro código. La mayoría de nosotros ha utilizado console.log(), pero tiene otras muchas funcionalidades.

Matrices dispersas o sparse arrays en JS

Una característica que puede producir algunos problemas, si no lo tenemos en cuenta, es la posibilidad de tener matrices con huecos, es decir, con algunos de sus elementos sin definir. Es lo que se suele denominar una matriz dispersa o sparse array. Veamos cómo trabajar con esta características de las matrices.

Algunos operadores de bits usados con asiduidad

Cada día más a menudo podemos encontrar operadores binarios utilizados como formas abreviadas de algunas operaciones que de otra forma sería algo menos compactas y, quizás, más comprensibles. Veamos algunos casos en detalle.

Cómo diferenciar arrow function de function

En un reciente artículo Javier Vélez Reyes hace patente las principales diferencias entre las funciones tradicionales y las funciones flecha, ya que ambos modelos no son equivalentes e intercambiables. Veamos cómo es posible saber si una función ha sido construida por medio de la instrucción function o como una arrow function.

Los misterios de length

Aumentar o reducir el tamaño

El hecho de que length tenga el tamaño de la matriz y los índices de la matriz empiecen por 0 ha dado a más de uno un disgusto. Es una convención a la que hay que acostumbrarse, los índices empiezan en 0 y terminan en length - 1.

Este no es el gran misterio que esconde length, lo más curioso es que esta no es una propiedad de sólo lectura, es una propiedad que podemos escribir y producir efectos sobre el Array.

Si incrementamos el valor de length estaremos incrementando el número de elementos.

var matriz = [1, 2, 3];
matriz.length = 5;
var vacia = [];
vacia.length = 10;

De igual forma, si reducimos el valor de length, estaremos eliminado los elementos del Array que estén por encima del nuevo valor.

var matriz = [1,2,3,4,5,6,7,8,9,10];
matriz.length = 3;

No es muy recomendable aprovechar esta curiosa característica y en general deberíamos tratar length como una propiedad de sólo lectura.

Asignar un nuevo valor por encima del último elemento definido

Si por algún motivo asignamos un elemento en una posición superior al último elemento del Array, la matriz crecerá automáticamente de tamaño. Si nos hemos saltado algún elemento, estos elementos intermedios quedarán como no definidos y tendremos una matriz dispersa.

var matriz = [1,2,3];
matriz[9] = 10;
console.log(matriz);		// [ 1, 2, 3, , , , , , , 10 ]
console.log(matriz.length);	// 10

Aprovechando esta característica se puede añadir un elemento al final de la matriz de la siguiente forma:

var vacia = [];
vacia[vacia.length] = 1;
vacia[vacia.length] = 2;
vacia[vacia.length] = 3;
console.log(vacia); // [1, 2, 3]
console.log(vacia.length); // 3

Debemos tener cuidado con incrementar el tamaño de una matriz sin darnos cuenta, ya que la creación de una matriz dispersa puede ser fuente de problemas y comportamientos no deseados.

delete y length

Con la instrucción delete se puede borrar una variable o un elemento de un Array. Cuando se usa con un Array hay que tener en cuenta que no modifica el valor de length, aunque borremos al último elemento, manteniéndose el tamaño de la matriz. Como consecuencia del uso de delete se genera una matriz dispersa, es decir, con alguno de sus valores sin definir.

var matriz = [1,2,3,4,5];

delete matriz[4];
console.log(matriz);        // [ 1, 2, 3, 4,  ]
console.log(matriz.length); // 5

delete matriz[0];
console.log(matriz);        // [ , 2, 3, 4,  ]
console.log(matriz.length); // 5

Es uso de delete está poco extendido. En el caso de utilizarlo con matrices debemos tener en cuenta su comportamiento y comprender que no estamos variando en ningún momento su tamaño-

Métodos del objeto Array

Vamos a dar un repaso a los diferentes modelos de métodos que tiene el objeto Array. Siguen varios patrones y no son siempre evidentes. Vamos a dar un repaso general a todos los métodos viendo que parámetros recibe, que valor devuelve, si modifican o no la matriz desde la que son llamadas y cómo se comportan con las matrices dispersas. También incluiremos una breve referencia desde que versión de ECMAScript está soportado y que navegadores y entornos lo tienen disponible.

En vez de una lista alfabética vamos a agrupar los métodos por temas a fin de dar una mayor comprensión a su funcionamiento y características.

Ampliar o reducir el Array

Para añadir y eliminar elementos del Array disponemos del siguiente conjunto de métodos:

MétodoDescripciónRetornoModifica
la matriz
Matrices dispersasSoporte
Array.prototype.pop()devuelve el último elemento de una matriz y lo elimina de la mismaúltimo elemento de la matrizGestiona los elementos no definidosES3. Chrome, Firefox, IE, Opera, Safari, Node
Array.prototype.push(element1, [element2], […])añade nuevos elementos al final de la matriz y devuelve el nuevo tamaño de la mismanuevo tamaño de la matrizMantiene los elementos no definidosES3. Chrome, Firefox, IE, Opera, Safari, Node
Array.prototype.shift()devuelve el primer elemento de una matriz y lo elimina de la mismael elemento eliminadoGestiona los elementos no definidosES3. Chrome, Firefox, IE, Opera, Safari, Node
Array.prototype.unshift(element1, [element2], […])añade nuevos elementos al principio de la matriz y devuelve el nuevo tamaño de la mismanuevo tamaño de la matrizMantiene los elementos no definidosES3. Chrome, Firefox, IE, Opera, Safari, Node
Array.prototype.concat(value1, [value N])crea una nueva matriz uniendo los valores de la matriz desde la que es invocado con las matrices o valores pasados como parámetrosnueva matriz con los datos combinadosNoMantiene los elementos no definidosES3. Chrome 1, Firefox 1, IE 5.5, Opera, Safari, Node
Array.prototype.slice([start], [end])devuelve una parte de una matriznueva matriz con la parte extraídaNoMantiene los elementos no definidosES3. Chrome, Firefox, IE, Opera, Safari, Node
Array.prototype.splice([start], [count], [element1], [element2], […]) cambia el contenido de la matriz, eliminando elementos y añadiendo otrosnueva matriz con los elementos eliminadosMantiene los elementos no definidosES3. Chrome, Firefox, IE, Opera, Safari, Node

Si nos fijamos, la primera sorpresa viene al comprobar que todos los métodos menos concat() modifican la matriz original. Este método devuelve una nueva matriz con los elementos añadidos y mantiene intacta la matriz original. Por este motivo concat() es utilizado en ocasiones para copiar un Array en otro.

Si queremos modificar la matriz original añadiendo nuevos elementos debemos utilizar push() o splice().

var matriz1 = [1,2,3,4,5];
var result1 = matriz1.concat(6, 7, 8, 9);
console.log(matriz1);   // [ 1, 2, 3, 4, 5 ]
console.log(result1);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

var matriz2 = [1,2,3,4,5];
matriz2.push(6,7,8,9);
console.log(matriz2);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

var matriz3 = [1,2,3,4,5];
matriz3.splice(matriz3.length, 0, 6, 7,8,9);
console.log(matriz3);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

Hay otra importante diferencia entre concat(), push() y splice(): el método concat() cambia de comportamiento si lo que recibe por parámetro es una matriz o si recibe otro tipo de valor. Si recibe una matriz anexa cada uno de los valores y no un solo valor como matriz anidada. Por el contrario, si push() y splice() reciben una matriz la incorporan como un solo elemento de tipo Array.

var matriz1 = [1,2,3,4,5];
var result2 = matriz1.concat( [6, 7,8,9] );
console.log(matriz1);   // [ 1, 2, 3, 4, 5 ]
console.log(result2);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

var matriz2 = [1,2,3,4,5];
matriz2.push([6,7,8,9]);
console.log(matriz2);   // [ 1, 2, 3, 4, 5, [ 6, 7, 8, 9 ] ]

var matriz3 = [1,2,3,4,5];
matriz3.splice(matriz3.length, 0, [6, 7,8,9]);
console.log(matriz3);   // [ 1, 2, 3, 4, 5, [ 6, 7, 8, 9 ] ]

Si queremos añadir un Array en otro Array podemos utilizar push() o splice(), pero tenemos que hacer algo más. En ES6 podemos utilizar el operador (spread) y en ES5.1 o anteriores utilizaremos Array.prototype.push.apply() o Array.prototype.splice.apply(). En ambos casos la matriz se convierte en los parámetros individuales.

// ES6
var matriz4 = [1,2,3,4,5];
matriz4.push(...[6,7,8,9]);
console.log(matriz4); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

// ES3
var matriz5 = [1,2,3,4,5];
Array.prototype.push.apply(matriz5, [6,7,8,9]);
console.log(matriz5); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

// ES6
var matriz6 = [1,2,3,4,5];
matriz6.splice(matriz6.length, 0, ...[6,7,8,9]);
console.log(matriz6); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

// ES3
var matriz7 = [1,2,3,4,5];
Array.prototype.splice.apply(matriz7, [matriz7.length, 0].concat([6,7,8,9]));
console.log(matriz7); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

Otra diferencia que igual se nos ha escapado es que slice() utiliza como parámetros start, end y splice() utiliza start, count, es decir, en el primer caso indicamos los índices del primer y último elemento que vamos a obtener, mientras que en el segundo caso indicamos el índice del primer elemento y cuantos elementos queremos extraer.

var matriz = [1,2,3,4,5];

var result1 = matriz.slice(1,3);
console.log(result1); // [ 2, 3 ]

var result2 = matriz.splice(1,3);
console.log(result2); // [ 2, 3, 4 ]

Buscar en el Array

Para buscar en un Array disponemos de los siguientes métodos:

MétodoDescripciónRetornoModifica
la matriz
Matrices dispersasSoporte
Array.prototype.find(callback, [thisArg])devuelve un valor de la matriz si la función pasada devuelve true para ese elemento o undefined en caso contrariovalor del elemento encontradoNoGestiona los elementos no definidosES6. Chrome 45, Firefox 25, Edge, Safari 7.1, Node 4
Array.prototype.findIndex(callback, [thisArg])Devuelve el índice de la matriz si la función pasada devuelve true para ese elemento o -1 en caso contrarioíndice del elemento encontradoNoGestiona los elementos no definidosES6. Chrome 45, Firefox 25, Edge, Safari 7.1, Node 4
Array.prototype.indexOf(searchElement, [fromIndex])devuelve índice del primer elemento que coincide o -1 si no se encuentraíndice del elemento encontradoNoIgnora los elementos no definidosES5.1. Chrome, Firefox, IE 9, Opera, Safari, Node
Array.prototype.lastIndexOf(searchElement, [fromIndex])devuelve el índice del último elemento que coincide o -1 si no se encuentraíndice del elementoNoIgnora los elementos no definidosES5.1. Chrome, Firefox, IE 9, Opera, Safari, Node
Array.prototype.hasOwnProperty(index)comprueba si una propiedad está creada en el objeto y se puede utilizar para comprobar si un índice está creado en la matriztrue / falseNoIgnora los elementos no definidos 

Tenemos que tener en cuenta los diferentes comportamientos a la hora de trabajar con matrices dispersas. IndexOf() y lastIndexOf() no tienen en cuenta los elementos no definidos de una matriz, mientras que la función callback de find() y findIndex() sí serán invocadas para los elementos no definidos.

var matriz = [1,2,3, ,5];

var result1 = matriz.indexOf(undefined);
console.log(result1); // -1

var result2 = matriz.lastIndexOf(undefined);
console.log(result2); // -1

var result3 = matriz.find(function(item, index, arr) {
   if (item === undefined) {
        return true;
    }
});
console.log(result3); // undefined

var result4 = matriz.findIndex(function(item, index, arr) {
    if (item === undefined) {
        return true;
    }
});
console.log(result4); // 3

Recorrer la matriz

Disponemos de un buen conjunto de instrucciones y métodos para trabajar con un Array recorriendo todos sus elementos.

Instrucción / MétodoDescripciónRetornoModifica
la matriz
Matrices dispersasSoporte
for ([initialization]; [condition]; [final-expression])bucle que se ejecuta mientras la condición sea verdaderaN/AN/AProcesa los elementos no definidosES1. Chrome, Firefox, IE 9, Opera, Safari, Node
for (variable in array)bucle que se ejecuta para todos los elementos enumerables de la matriz, incluidas propiedades enumerables que pueda tener como objetoN/AN/AProcesa los elementos no definidosES1. Chrome, Firefox, IE 9, Opera, Safari, Node
for (variable of iterable)bucle que se ejecuta para todos los elementos de la matriz llamando implícitamente a <code>myArray[Symbol.iterable]()</code>N/AN/AIgnora los elementos no definidosES6. Chrome 38, Firefox 13, Edge 12, Opera 12, Safari 7.1, Node 0.12
Array.prototype.forEach(callback, [thisArg])ejecuta la función pasada para cada elemento de la matrizundefinedNoIgnora los elementos no definidosES5.1. Chrome, Firefox, IE 9, Opera, Safari, Node
Array.prototype.filter(callback, [thisArg])crea una nueva matriz con todos los elementos que la función pasada devuelva truenueva matriz con los elementos para los que la función ha devuelto trueNoIgnora los elementos no definidos y los elimina de la matriz devueltaES 5.1. Chrome, Firefox 1.5, IE 9, Opera, Safari, Node
Array.prototype.map()crea una matriz con los resultados la función a la que se le pasa cada uno de los elementos de la matriz originalnueva matriz con los elementos modificadosNoIgnora los elementos no definidos y los mantiene en la matriz devueltaES5.1. Chrome, Firefox, IE 9, Opera, Safari, Node
Array.prototype.reduce()aplica una función a todos los elementos de la matriz y devuelve el resultado en un acumuladorvalor devuelto por la última ejecución de la funciónNoIgnora los elementos no definidosES5.1. Chrome, Firefox, IE 9, Opera, Safari, Node
Array.prototype.reduceRight()aplica una función a todos los elementos de la matriz, de mayor a menor índice, y devuelve el resultado en un acumuladorvalor devuelto por la última ejecución de la funciónNoIgnora los elementos no definidosES5.1. Chrome, Firefox, IE 9, Opera, Safari, Node
Array.prototype.every(callback, [thisArg])comprueba si para todos los elementos de la matriz la función pasada como parámetro devuelve truetrue / falseNoIgnora los elementos no definidosES5.1. Chrome, Firefox 5.1, IE9, Opera, Safari, Node
Array.prototype.some()verifica si para algún elemento de la matriz la función pasada devuelve truetrue / falseNoIgnora los elementos no definidosES1. Chrome, Firefox, IE 9, Opera, Safari, Node

En primer lugar, tenemos que diferenciar dos grandes bloques: los bucles for y for of tienen en cuenta a los elementos no definidos de las matrices dispersas, mientras que for in y el resto de los métodos ignoran los elementos no definidos.

var matriz = ['red', 'orange', 'yellow', , 'blue', 'purple'];

for (var n = 0; n &lt; matriz.length; n++) {
    console.log(matriz[n]);         // red orange yellow undefined blue purple
}

for (var i in matriz) {
    console.log(matriz[i]);         // red orange yellow blue purple
}

for (var e of matriz) {
    console.log(e);                 // red orange yellow undefined blue purple
}

matriz.forEach(function(item, index, arr) {
    console.log(item);              // red orange yellow blue purple
});

Un caso bastante curioso lo constituyen map() y filter(). Ninguno de los dos métodos pasa los elementos no definidos a la función que reciben como parámetro, pero el resultado es diferente en cada caso. En map() los elementos no definidos se mantienen, mientras que con filter() los elementos no definidos son eliminados de la matriz resultante.

var matriz = ['red', 'orange', 'yellow', , 'blue', 'purple'];

var result1 = matriz.map(function(item, index, arr) {
    console.log(item);              // red orange yellow blue purple
    return item;
});
console.log(result1);               // [ 'red', 'orange', 'yellow', , 'blue', 'purple' ]

var result2 = matriz.filter(function(item, index, arr) {
console.log(item);                  // red orange yellow blue purple
    return true;
});
console.log(result2);               // [ 'red', 'orange', 'yellow', 'blue', 'purple' ]

Modificar el contenido de las matrices

Disponemos de varios métodos para modificar el contenido de la matriz sin alterar su tamaño.

MétodoDescripciónRetornoModifica
la matriz
Matrices dispersasSoporte
Array.prototype.copyWithin(target, [start], [end])copia parte de una matriz en otra posición de la misma matrizla matriz transformadaMantiene los elementos no definidosES6. Chrome 45, Firefox 32, Edge 12, Node 4
Array.prototype.fill(value, [start], [end])rellena los elementos de una matriz con un valorla matriz transformadaRellena los elementos no definidosES6. Chrome 45. Firefox 31, Edge, Safari 8. Node 4
Array.prototype.sort([callback])ordena los elementos de una matriz y la devuelvela matriz transformadaMantiene los elementos no definidosES1. Chrome, Firefox, IE, Opera, Safari, Node
Array.prototype.reverse()mueve los elementos de una matriz para que se sitúen en orden inverso al originalla matriz transformadaMantiene los elementos no definidosES1. Chrome, Firefox, IE, Opera, Safari, Node

Como podemos ver, copyWithin() y fill() siguen el formato de slice() de utilizar start y end como parámetros, a diferencia de splice() que se queda sólo en el formato de parámetros start y count.

Todos estos métodos modifican la matriz y además la devuelven, a diferencia de los métodos del grupo anterior que devuelven una nueva matriz sin modificar la original. Esta diferencia de comportamiento hace que veamos en muchas ocasiones códigos donde se asigna el retorno de estos métodos a la matriz original, aunque realmente no es realmente necesario:

var matriz = ['red', 'orange', 'yellow', 'green' , 'blue', 'purple'];
matriz = matriz.sort();

Estos métodos trabajan sin problemas con los elementos no definidos de una matriz dispersas, si bien tenemos un caso especial con sort(), ya que los valores no definidos no serán pasados a la función que pasamos como parámetro para realizar la ordenación y serán situados al final de la nueva matriz.

var dispersa = ['red', 'orange', 'yellow', , 'blue', 'purple'];
dispersa.sort(function(prev, next) {
    console.log(prev, next);    // nunca se muestra undefined
    return prev&gt; next;
});
console.log(dispersa);          // [ 'blue', 'orange', 'purple', 'red', 'yellow',  ] 

Este comportamiento resulta bastante confuso y es muy posible que no nos esperemos encontrar los elementos definidos al final de la matriz tras una ordenación.

Array y String

MétodoDescripciónRetornoModifica
la matriz
Matrices dispersasSoporte
Array.prototype.join()une todos los elementos de la matriz en una cadenacadenaNoIncluye los elementos no definidos como una cadena vacíaES1. Chrome, Firefox, IE, Opera, Safari, Node
String.prototype.split([separator], [limit])devuelve una matriz con las cadenas resultante de dividir la cadena por un separador pasado como parámetronueva matrizN/AES1. Chrome, Firefox, IE, Opera, Safari, Node
Array.prototype.toString()cada elemento se convierte en cadena y se concatenan todas ellas separadas por comascadenaNoIncluye los elementos no definidos como una cadena vacíaES1. Chrome, Firefox, IE, Opera, Safari, Node

En este caso join() convierte los elementos no definidos de una matriz dispersa en una cadena vacía. Por el contrario, split() no convierte una cadena vacía en un elemento no definido, si no en un elemento que contiene una cadena vacía.

Iteradores

En ES6 han aparecido nuevos métodos para trabajar con iteradores a partir de un Array.

MétodoDescripciónRetornoModifica
la matriz
Matrices dispersasSoporte
Array.form(arrayLike, [mapFn], [thisArg])crea una matriz desde un objeto iterablenueva matrizn/an/aES6. Chrome 45, Firefox 32, Edge, Safari 9, Node 4
Array.prototype[Symbol.iterable]()obtiene un objeto iterable desde una matrizobjeto iterable con os valoresNoGestiona los elementos no definidosES6. Chrome 38, Firefox 36, Edge, Node 0.12
Array.prototype.entries()devuelve un objeto iterable que contiene los pares clave-valor de cada uno de los elementos de la matrizobjeto iterable con los índices y valoresNoGestiona los elementos no definidosES6. Chrome 38, Firefox 28, Edge, Node 0.12
Array.prototype.values()devuelve una matriz con todos los valores de la matrizobjeto iterable con los valoresNoGestiona los elementos no definidosES6. Edge, Opera 25, Safari 9

En todos los casos los elementos no definidos de una matriz dispersa son gestionados sin problemas por los métodos del objeto Array.

var matriz = [1,2, , 4, 5];
for (var n of matriz.entries() ) {
    console.log(n);     // [ 0, 1 ]  [ 1, 2 ]  [ 2, undefined ]  [ 3, 4 ]  [ 4, 5 ]
}

for (var i of matriz.values() ) {
    console.log(i);     // 1   2   undefined   4   5
}

for (var e of matriz[Symbol.iterator]() ) {
    console.log(e);     // 1   2   undefined   4   5
} 

Aunque pueda sorprender, a la fecha de este artículo values() no está implementado en Node o Chrome, aunque sí está disponible en Micosoft Edge, Opera y Apple Safari.

Por otra parte, no tiene sentido que Array.form() considere un valor undefined y cree una matriz dispersa, simplemente considera ese caso como un valor explícitamente definido como undefined y genera una matriz densa.

function* gen() {
    yield 1;
    yield 2;
    yield 3;
    yield;          // undefined
    yield 5;
}
var arr = Array.from(gen());
console.log(arr);   // [ 1, 2, 3, undefined, 5 ]

Comprobar el tipo

Array es el único objeto que tiene un método para comprobar si una determinada variable es de este tipo. Por medio de Array.isArray() podemos comprobar si el valor pasado por parámetro es de este tipo, pero no hay ninguna otro objeto de Javascript que tenga un método de este tipo, por lo que resulta una cierta rareza dentro del conjunto de métodos disponibles.

 

Conclusiones

Si hacemos un breve resumen de la situación nos encontramos que:

  • Podemos crear matrices dispersas con las expresiones literales [], pero no cuando indicamos varios parámetros a new Array() o Array.of()
  • new Array() y Array() si reciben un solo parámetro de tipo entero crean una matriz vacía con ese tamaño y con el nuevo Array.of() podemos crear una matriz de un solo elemento con un valor entero.
  • length es una propiedad de lectura y escritura y amplia o reduce el tamaño de la matriz.
  • Si asignamos un valor por encima del valor máximo de la matriz esta crece automáticamente, dejando los posibles valores intermedios como no definidos.
  • delete borra elementos de la matriz, pero no modifica el tamaño de la misma, dejando los elementos como no definidos.
  • Los métodos copyWithin(), fill() y slice() tiene los parámetros start y end y por el contrario splice() utiliza start y count.
  • Los métodos pop(), push(), shift(), unshift(), splice(), copyWithin(), fill(), sort() y reverse() modifican la matriz. concat(), slice(), filter() y map() no la modifican.
  • indexOf(), lastIndexOf(), hasOwnProperty(), for of, forEach(), filter(), map(), reduce(), reduceRight(), every() y some() ignoran los elementos no definidos. sort() no los pasa al callback, pero los mantiene al final de la matriz. Todos los demás métodos e instrucciones manejan y gestionan los datos no definidos de las matrices dispersas sin problemas.
  • El objeto Array es el único que dispone de un método para comprobar el tipo de una variable: Array.isArray().

Resulta complicado dar unas conclusiones ante esta situación. Está claro que las instrucciones y métodos para el manejo de las matrices no están regidos todas ellos por el mismo patrón y eso resulta bastante confuso, siendo motivo de equívocos e incluso errores en nuestro código.

La compatibilidad con versiones anteriores de ECMAScript hace que las nuevas versiones hereden los diseños y parámetros de funcionamiento anteriores. Parece que los nuevos diseños deberían ser más consistentes, pero aun así nos encontramos que métodos definidos en ES6 que funcionan de forma diferente en cuanto a las matrices dispersas. Seguramente los sabios que definen el lenguaje deben tener sus motivos para estos diseños, pero resulta difícil de comprenderlos por nosotros los sencillos programadores que intentamos sacar el máximo partido de Javascript.

Poco podemos hacer en la práctica más allá de conocer estas diferencias y tenerlas en cuenta en nuestros desarrollos.

Novedades

Comparación estricta y no estricta en Javascript

Aunque pueda parecer que comparar dos valores es algo sencillo y común, lo cierto es que comparar en Javascript conlleva algunas dificultades que debemos conocer, en especial la diferencia entre la comparación estricta y no estricta, es decir, la diferencia entre == (con sólo dos signos de igualdad) y === (con sólo tres signos de igualdad).

Sistema de pruebas minimalista en Javascript

En todos los navegadores modernos y en Node disponemos de console.assert() para comprobar el resultado de nuestras funciones y construir un sencillo conjunto de pruebas sin necesidad de instalar absolutamente nada. Es un sistema minimalista, sin dependencias y que funciona muy bien. Os animamos a conocer un poco más de esta pequeña herramienta.

Esquema de módulo Javascript para navegador y Node

Una de los requisitos cada día más común es que nuestro código debe poder funcionar sin problemas tanto en el navegador como en el servidor con Node. Esto puede parecer en principio algo sencillo, pero debemos tener en cuenta algunas características de cada uno de los entornos para construir un módulo que pueda funcionar correctamente en ambos contextos.

Progressive Web Apps – Jad Joubran

The web is becoming more and more powerful everyday, especially with the launch of Progressive Web Apps. PWAs are experiences that combine the best of the web and the best of apps. You can now build web apps that run from your home screen, receive push notifications & work offline.

breves

Descrubir algunas características de console

En el día a día nos encontramos muy a menudo utilizando console. Es una navaja multiusos que nos facilita la vida a la hora de depurar nuestro código. La mayoría de nosotros ha utilizado console.log(), pero tiene otras muchas funcionalidades.

Matrices dispersas o sparse arrays en JS

Una característica que puede producir algunos problemas, si no lo tenemos en cuenta, es la posibilidad de tener matrices con huecos, es decir, con algunos de sus elementos sin definir. Es lo que se suele denominar una matriz dispersa o sparse array. Veamos cómo trabajar con esta características de las matrices.

Algunos operadores de bits usados con asiduidad

Cada día más a menudo podemos encontrar operadores binarios utilizados como formas abreviadas de algunas operaciones que de otra forma sería algo menos compactas y, quizás, más comprensibles. Veamos algunos casos en detalle.

Cómo diferenciar arrow function de function

En un reciente artículo Javier Vélez Reyes hace patente las principales diferencias entre las funciones tradicionales y las funciones flecha, ya que ambos modelos no son equivalentes e intercambiables. Veamos cómo es posible saber si una función ha sido construida por medio de la instrucción function o como una arrow function.