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
HTTP2 para programadores. Enviar mensajes del servidor al cliente con Server Sent Event (sin WebSockets)
En esta charla, organizada por MadridJS, Pablo Almunia nos muestra cómo la mayoría de nosotros cuando oímos hablar por primera vez de HTTP2 nos ilusionamos con las posibilidades que presumiblemente se abrían para el desarrollo de soluciones web avanzadas y cómo muchos nos sentimos defraudados con lo que realmente se podía implementar.
En esta charla podemos ver cómo funciona el HTTP2, que debemos tener en cuenta en el servidor para hace uso de este protocolo y, sobre todo, cómo podemos enviar información desde el servidor al cliente de forma efectiva y fácil. Veremos con detenimiento cómo por medio de los Server-Sent Events (SSE) podemos recibir en el cliente datos enviados desde el servidor sin utilizar websocket, simplificando enormemente la construcción de aplicaciones con comunicación bidireccional.
Observables en Javascript con Proxies
En esta charla, organizada por MadridJS, Pablo Almunia nos habla de la observación reactiva de objetos en Javascript por medio de Proxy. Se describe paso a paso cómo funcionan los Proxies y en que casos pueden ser nuestro mejor aliado. Veremos que no hay que tenerles miedo, son bastante sencillos de utilizar, y nos ofrecen una gran abanico de posibilidades.
Aplicaciones JAMStack, SEO friendly y escalables con NextJS
En esta charla de Madrid JS, Rafael Ventura nos describe las funcionalidades clave de NextJS, nos muestra en vivo cómo desarrollar una completa aplicación JAMStack con Server Side Rendering (SSR) y Static Site Generation (SSG) y termina mostrando como publicar esta aplicación en Vercel.
Stencil JS: mejora el Time To Market de tu producto, por Rubén Aguilera
En esta charla Rubén Aguilera nos cuenta los problemas que tienen muchas empresas a la hora de sacar productos accesibles, vistosos y usables en el Time To Market que requiere Negocio y cómo podemos minimizar este tiempo gracias al DevUI con StencilJS para adecuar una aplicación de Angular a las exigencias del mercado en tiempo record.
breves
Javascript: 25 aniversario
25 años con Javascript han dado para mucho. Pero todavía queda mucho para este lenguaje de programación.
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.
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.
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étodo | Descripción | Retorno | Modifica la matriz | Matrices dispersas | Soporte |
Array.prototype.pop() | devuelve el último elemento de una matriz y lo elimina de la misma | último elemento de la matriz | Sí | Gestiona los elementos no definidos | ES3. 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 misma | nuevo tamaño de la matriz | Sí | Mantiene los elementos no definidos | ES3. Chrome, Firefox, IE, Opera, Safari, Node |
Array.prototype.shift() | devuelve el primer elemento de una matriz y lo elimina de la misma | el elemento eliminado | Sí | Gestiona los elementos no definidos | ES3. 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 misma | nuevo tamaño de la matriz | Sí | Mantiene los elementos no definidos | ES3. 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ámetros | nueva matriz con los datos combinados | No | Mantiene los elementos no definidos | ES3. Chrome 1, Firefox 1, IE 5.5, Opera, Safari, Node |
Array.prototype.slice([start], [end]) | devuelve una parte de una matriz | nueva matriz con la parte extraída | No | Mantiene los elementos no definidos | ES3. Chrome, Firefox, IE, Opera, Safari, Node |
Array.prototype.splice([start], [count], [element1], [element2], […]) | cambia el contenido de la matriz, eliminando elementos y añadiendo otros | nueva matriz con los elementos eliminados | Sí | Mantiene los elementos no definidos | ES3. 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étodo | Descripción | Retorno | Modifica la matriz | Matrices dispersas | Soporte |
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 contrario | valor del elemento encontrado | No | Gestiona los elementos no definidos | ES6. 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 encontrado | No | Gestiona los elementos no definidos | ES6. 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 encontrado | No | Ignora los elementos no definidos | ES5.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 elemento | No | Ignora los elementos no definidos | ES5.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 matriz | true / false | No | Ignora 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étodo | Descripción | Retorno | Modifica la matriz | Matrices dispersas | Soporte |
for ([initialization]; [condition]; [final-expression]) | bucle que se ejecuta mientras la condición sea verdadera | N/A | N/A | Procesa los elementos no definidos | ES1. 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 objeto | N/A | N/A | Procesa los elementos no definidos | ES1. 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/A | N/A | Ignora los elementos no definidos | ES6. 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 matriz | undefined | No | Ignora los elementos no definidos | ES5.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 true | nueva matriz con los elementos para los que la función ha devuelto true | No | Ignora los elementos no definidos y los elimina de la matriz devuelta | ES 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 original | nueva matriz con los elementos modificados | No | Ignora los elementos no definidos y los mantiene en la matriz devuelta | ES5.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 acumulador | valor devuelto por la última ejecución de la función | No | Ignora los elementos no definidos | ES5.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 acumulador | valor devuelto por la última ejecución de la función | No | Ignora los elementos no definidos | ES5.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 true | true / false | No | Ignora los elementos no definidos | ES5.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 true | true / false | No | Ignora los elementos no definidos | ES1. 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 < 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étodo | Descripción | Retorno | Modifica la matriz | Matrices dispersas | Soporte |
Array.prototype.copyWithin(target, [start], [end]) | copia parte de una matriz en otra posición de la misma matriz | la matriz transformada | Sí | Mantiene los elementos no definidos | ES6. Chrome 45, Firefox 32, Edge 12, Node 4 |
Array.prototype.fill(value, [start], [end]) | rellena los elementos de una matriz con un valor | la matriz transformada | Sí | Rellena los elementos no definidos | ES6. Chrome 45. Firefox 31, Edge, Safari 8. Node 4 |
Array.prototype.sort([callback]) | ordena los elementos de una matriz y la devuelve | la matriz transformada | Sí | Mantiene los elementos no definidos | ES1. Chrome, Firefox, IE, Opera, Safari, Node |
Array.prototype.reverse() | mueve los elementos de una matriz para que se sitúen en orden inverso al original | la matriz transformada | Sí | Mantiene los elementos no definidos | ES1. 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> 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étodo | Descripción | Retorno | Modifica la matriz | Matrices dispersas | Soporte |
Array.prototype.join() | une todos los elementos de la matriz en una cadena | cadena | No | Incluye los elementos no definidos como una cadena vacía | ES1. 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ámetro | nueva matriz | N/A | ES1. Chrome, Firefox, IE, Opera, Safari, Node | |
Array.prototype.toString() | cada elemento se convierte en cadena y se concatenan todas ellas separadas por comas | cadena | No | Incluye los elementos no definidos como una cadena vacía | ES1. 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étodo | Descripción | Retorno | Modifica la matriz | Matrices dispersas | Soporte |
Array.form(arrayLike, [mapFn], [thisArg]) | crea una matriz desde un objeto iterable | nueva matriz | n/a | n/a | ES6. Chrome 45, Firefox 32, Edge, Safari 9, Node 4 |
Array.prototype[Symbol.iterable]() | obtiene un objeto iterable desde una matriz | objeto iterable con os valores | No | Gestiona los elementos no definidos | ES6. 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 matriz | objeto iterable con los índices y valores | No | Gestiona los elementos no definidos | ES6. Chrome 38, Firefox 28, Edge, Node 0.12 |
Array.prototype.values() | devuelve una matriz con todos los valores de la matriz | objeto iterable con los valores | No | Gestiona los elementos no definidos | ES6. 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 anew Array()
oArray.of()
new Array()
yArray()
si reciben un solo parámetro de tipo entero crean una matriz vacía con ese tamaño y con el nuevoArray.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()
yslice()
tiene los parámetrosstart
yend
y por el contrariosplice()
utilizastart
ycount
. - Los métodos
pop()
,push()
,shift()
,unshift()
,splice()
,copyWithin()
,fill()
,sort()
yreverse()
modifican la matriz.concat()
,slice()
,filter()
ymap()
no la modifican. indexOf()
,lastIndexOf()
,hasOwnProperty()
,for of
,forEach()
,filter()
,map()
,reduce()
,reduceRight()
,every()
ysome()
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
HTTP2 para programadores. Enviar mensajes del servidor al cliente con Server Sent Event (sin WebSockets)
En esta charla, organizada por MadridJS, Pablo Almunia nos muestra cómo la mayoría de nosotros cuando oímos hablar por primera vez de HTTP2 nos ilusionamos con las posibilidades que presumiblemente se abrían para el desarrollo de soluciones web avanzadas y cómo muchos nos sentimos defraudados con lo que realmente se podía implementar.
En esta charla podemos ver cómo funciona el HTTP2, que debemos tener en cuenta en el servidor para hace uso de este protocolo y, sobre todo, cómo podemos enviar información desde el servidor al cliente de forma efectiva y fácil. Veremos con detenimiento cómo por medio de los Server-Sent Events (SSE) podemos recibir en el cliente datos enviados desde el servidor sin utilizar websocket, simplificando enormemente la construcción de aplicaciones con comunicación bidireccional.
Observables en Javascript con Proxies
En esta charla, organizada por MadridJS, Pablo Almunia nos habla de la observación reactiva de objetos en Javascript por medio de Proxy. Se describe paso a paso cómo funcionan los Proxies y en que casos pueden ser nuestro mejor aliado. Veremos que no hay que tenerles miedo, son bastante sencillos de utilizar, y nos ofrecen una gran abanico de posibilidades.
Aplicaciones JAMStack, SEO friendly y escalables con NextJS
En esta charla de Madrid JS, Rafael Ventura nos describe las funcionalidades clave de NextJS, nos muestra en vivo cómo desarrollar una completa aplicación JAMStack con Server Side Rendering (SSR) y Static Site Generation (SSG) y termina mostrando como publicar esta aplicación en Vercel.
Stencil JS: mejora el Time To Market de tu producto, por Rubén Aguilera
En esta charla Rubén Aguilera nos cuenta los problemas que tienen muchas empresas a la hora de sacar productos accesibles, vistosos y usables en el Time To Market que requiere Negocio y cómo podemos minimizar este tiempo gracias al DevUI con StencilJS para adecuar una aplicación de Angular a las exigencias del mercado en tiempo record.
breves
Javascript: 25 aniversario
25 años con Javascript han dado para mucho. Pero todavía queda mucho para este lenguaje de programación.
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.
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.
Excelente aporte guste mucho de como esta todo explicado