En JavaScript existe un tipo especial de objeto llamado comunmente array-like
(parecido a un array) y es que a la vista parece ser un array, valores separados por comas, encerrados en corchetes, se puede accedr a sus elementos con \$&i\$&
. Sin embargo, cuando intentamos usar métodos como .map()``.reduce()``.slice()
, etc el intérprete nos arroja un error, demostrandonos que no estamos realmente frente a un array. Y cuando comenzamos con JavaScript no conocer este detalle puede ser realmente frustrante.
El caso más conocido es el objeto arguments
que lista los argumentos pasados al ejecutar una función. Supongamos que queremos obtener la suma de todos los argumentos pasados a una función. Sin importar cuántos son:
1let sum = function(){ 2 arguments.reduce((a,b) => a + b); 3} 4 5console.log(sum(1,2,3)); // TypeError: arguments.reduce is not a function 6
Puesto que no es una array y no podemos usar .reduce()
no nos queda más que iterar:
1let sum = function(){ 2 let total = 0; 3 for(let i = 0; i < arguments.length; i++) { 4 total += arguments[i]; 5 } 6 return total; 7} 8 9console.log(sum(1,2,3)) // 6 10
¿Y los parámetros rest en ES6?
Los parámetros rest en ES6 indican que una función puede recibir un número indefinido de argumentos. Y la ventaja frente a arguments
es que este es un array, no un array-like. Veamos el ejemplo nuevamente:
1let sum = function(...args){ 2 return args.reduce((a,b) => a + b); 3} 4 5console.log(sum(1,2,3)); // 6 6
Objetos array-like y el DOM
Cuando interactuamos con el DOM por ejemplo con document.querySelectorAll()
, element.classList
, element.children
, etc. recibimos nuevamente un array-like, no un array, aunque lo parezca. Técnicamente recibimos un NodeList o un DOMTokenList.
Convertir un array-like a un array
Para el caso anterior (manipular el DOM) se hace necesario convertir los objetos array-like a arrays para poder operar sobre ellos. De hecho, jQuery nos facilita ese trabajo:
1$('a').css('color', 'green'); 2
Pero lo siguiente no funcionará en Vanilla JS:
1let links = document.querySelectorAll('a'); 2links.map(link => link.style.color = 'red') 3
Para convertirlo en un array real usaremos el método .slice
de Array.prototipe
Este método crea una copia comor array y el método .apply
nos permite pasar el objeto original al que se aplicará .slice()
.
1let linksArr = Array.prototype.slice.apply(links) 2
Por tanto, con Vanilla JS, el ejemplo anterior que usaba jQuery quedaría así:
1let links = document.querySelectorAll('a'); 2let linksArr = Array.prototype.slice.apply(links); 3linksArr.map(link => link.style.color = 'red'); 4