Ir al contenido principal

Métodos principales de arrays

Introducción

Los arrays en JavaScript no son simples contenedores de datos; están equipados con una rica colección de métodos integrados que permiten manipular, transformar y analizar la información que contienen de formas muy potentes. Estos métodos convierten a los arrays en una de las estructuras de datos más versátiles del lenguaje.

En el artículo anterior, exploramos cómo crear arrays y acceder a sus elementos. Ahora, profundizaremos en los métodos principales que nos ofrece JavaScript para trabajar con arrays, desde operaciones básicas como añadir o eliminar elementos, hasta transformaciones más complejas y búsquedas avanzadas. Dominar estos métodos es fundamental para escribir código más eficiente, legible y expresivo.

A lo largo de este artículo, veremos cómo estos métodos pueden simplificar tareas que de otro modo requerirían múltiples líneas de código, permitiéndonos centrarnos en la lógica de nuestras aplicaciones en lugar de en los detalles de implementación.

Métodos para añadir/eliminar elementos

push() y pop()

Estos métodos permiten trabajar con el final del array, tratándolo como una estructura de datos de tipo pila (stack):

const frutas = ["manzana", "plátano"];

// push(): añade uno o más elementos al final del array y devuelve la nueva longitud
const nuevaLongitud = frutas.push("naranja", "fresa");
console.log(frutas); // ["manzana", "plátano", "naranja", "fresa"]
console.log(nuevaLongitud); // 4

// pop(): elimina el último elemento y lo devuelve
const ultimaFruta = frutas.pop();
console.log(frutas); // ["manzana", "plátano", "naranja"]
console.log(ultimaFruta); // "fresa"

shift() y unshift()

Estos métodos trabajan con el principio del array:

const colores = ["rojo", "verde", "azul"];

// unshift(): añade uno o más elementos al principio y devuelve la nueva longitud
const nuevaLongitud = colores.unshift("amarillo", "negro");
console.log(colores); // ["amarillo", "negro", "rojo", "verde", "azul"]
console.log(nuevaLongitud); // 5

// shift(): elimina el primer elemento y lo devuelve
const primerColor = colores.shift();
console.log(colores); // ["negro", "rojo", "verde", "azul"]
console.log(primerColor); // "amarillo"

Es importante tener en cuenta que shift() y unshift() son generalmente más lentos que push() y pop(), especialmente en arrays grandes, ya que requieren reindexar todos los elementos.

Métodos de ordenación y manipulación

sort()

El método sort() ordena los elementos de un array y devuelve el array ordenado. Por defecto, convierte los elementos a strings y los compara según su valor UTF-16:

const frutas = ["naranja", "manzana", "plátano", "fresa"];

// Ordenar alfabéticamente (comportamiento por defecto)
frutas.sort();
console.log(frutas); // ["fresa", "manzana", "naranja", "plátano"]

// IMPORTANTE: sort() modifica el array original

Para ordenar números, necesitamos proporcionar una función de comparación:

const numeros = [10, 5, 8, 1, 7];

// Sin función de comparación (incorrecto para números)
numeros.sort();
console.log(numeros); // [1, 10, 5, 7, 8] - orden lexicográfico incorrecto

// Con función de comparación (correcto para números)
numeros.sort((a, b) => a - b);
console.log(numeros); // [1, 5, 7, 8, 10] - orden numérico correcto

// Orden descendente
numeros.sort((a, b) => b - a);
console.log(numeros); // [10, 8, 7, 5, 1]

Ordenar objetos por una propiedad:

const personas = [
    { nombre: "Ana", edad: 28 },
    { nombre: "Carlos", edad: 22 },
    { nombre: "Beatriz", edad: 35 }
];

// Ordenar por edad (ascendente)
personas.sort((a, b) => a.edad - b.edad);
console.log(personas);
// [
//   { nombre: "Carlos", edad: 22 },
//   { nombre: "Ana", edad: 28 },
//   { nombre: "Beatriz", edad: 35 }
// ]

// Ordenar por nombre
personas.sort((a, b) => a.nombre.localeCompare(b.nombre));
console.log(personas);
// [
//   { nombre: "Ana", edad: 28 },
//   { nombre: "Beatriz", edad: 35 },
//   { nombre: "Carlos", edad: 22 }
// ]

reverse()

El método reverse() invierte el orden de los elementos de un array:

const letras = ["a", "b", "c", "d"];
letras.reverse();
console.log(letras); // ["d", "c", "b", "a"]

// IMPORTANTE: reverse() también modifica el array original

Un patrón común es combinar sort() y reverse():

const numeros = [3, 1, 4, 1, 5, 9];
numeros.sort((a, b) => a - b).reverse();
console.log(numeros); // [9, 5, 4, 3, 1, 1]

splice()

El método splice() permite añadir, eliminar o reemplazar elementos en cualquier posición del array:

const meses = ["Enero", "Febrero", "Abril", "Mayo"];

// splice(posición, cantidadAEliminar, ...elementosAInsertar)

// Insertar en posición 2 sin eliminar nada
meses.splice(2, 0, "Marzo");
console.log(meses); // ["Enero", "Febrero", "Marzo", "Abril", "Mayo"]

// Eliminar 1 elemento desde posición 4
const eliminados = meses.splice(4, 1);
console.log(meses); // ["Enero", "Febrero", "Marzo", "Abril"]
console.log(eliminados); // ["Mayo"]

// Reemplazar elementos (eliminar e insertar)
meses.splice(1, 2, "Nuevo mes", "Otro nuevo");
console.log(meses); // ["Enero", "Nuevo mes", "Otro nuevo", "Abril"]

splice() es muy versátil, pero modifica el array original. Devuelve un array con los elementos eliminados.

Métodos de búsqueda

indexOf() y lastIndexOf()

Estos métodos buscan un elemento y devuelven su posición:

const numeros = [10, 20, 30, 40, 30, 50];

// indexOf(): encuentra la primera ocurrencia
const primeraPosicion = numeros.indexOf(30);
console.log(primeraPosicion); // 2

// indexOf() con segundo parámetro (posición desde la que empezar a buscar)
const segundaBusqueda = numeros.indexOf(30, 3);
console.log(segundaBusqueda); // 4

// lastIndexOf(): encuentra la última ocurrencia
const ultimaPosicion = numeros.lastIndexOf(30);
console.log(ultimaPosicion); // 4

// Si el elemento no existe, devuelven -1
console.log(numeros.indexOf(100)); // -1

includes()

Introducido en ES7, includes() verifica si un array contiene un elemento específico:

const mascotas = ["perro", "gato", "conejo"];

console.log(mascotas.includes("gato")); // true
console.log(mascotas.includes("pez")); // false

// Segundo parámetro opcional: desde qué posición buscar
console.log(mascotas.includes("perro", 1)); // false (busca desde posición 1)

find() y findIndex()

Estos métodos, introducidos en ES6, permiten búsquedas más avanzadas usando una función de predicado:

const personas = [
    { id: 1, nombre: "Ana", edad: 28 },
    { id: 2, nombre: "Carlos", edad: 16 },
    { id: 3, nombre: "Elena", edad: 42 }
];

// find(): devuelve el primer elemento que cumple la condición
const adulto = personas.find(persona => persona.edad >= 18);
console.log(adulto); // { id: 1, nombre: "Ana", edad: 28 }

// findIndex(): devuelve el índice del primer elemento que cumple la condición
const indiceAdulto = personas.findIndex(persona => persona.edad >= 18);
console.log(indiceAdulto); // 0

// Si ningún elemento cumple la condición:
const anciano = personas.find(persona => persona.edad > 70);
console.log(anciano); // undefined

const indiceAnciano = personas.findIndex(persona => persona.edad > 70);
console.log(indiceAnciano); // -1

Métodos de transformación

join()

El método join() crea una cadena con todos los elementos del array, unidos por un separador:

const palabras = ["Hola", "mundo", "JavaScript"];

// Unir con un espacio
const frase = palabras.join(" ");
console.log(frase); // "Hola mundo JavaScript"

// Unir con otro separador
console.log(palabras.join("-")); // "Hola-mundo-JavaScript"

// Sin separador (une directamente)
console.log(palabras.join("")); // "HolamundoJavaScript"

// Separador por defecto (coma)
console.log(palabras.join()); // "Hola,mundo,JavaScript"

slice()

El método slice() extrae una sección de un array y devuelve un nuevo array, sin modificar el original:

const numeros = [1, 2, 3, 4, 5, 6];

// slice(inicio, fin) - no incluye el índice 'fin'
const porcion = numeros.slice(2, 4);
console.log(porcion); // [3, 4]
console.log(numeros); // [1, 2, 3, 4, 5, 6] - original sin cambios

// Sin parámetro 'fin' (hasta el final)
console.log(numeros.slice(3)); // [4, 5, 6]

// Con índice negativo (cuenta desde el final)
console.log(numeros.slice(-2)); // [5, 6]
console.log(numeros.slice(1, -2)); // [2, 3, 4]

// Clonar un array completo
const copia = numeros.slice();
console.log(copia); // [1, 2, 3, 4, 5, 6]

concat()

El método concat() combina dos o más arrays, creando un nuevo array sin modificar los originales:

const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const array3 = [7, 8];

// Concatenar arrays
const combinado = array1.concat(array2, array3);
console.log(combinado); // [1, 2, 3, 4, 5, 6, 7, 8]

// Los arrays originales no cambian
console.log(array1); // [1, 2, 3]

// También acepta valores individuales
const conValores = array1.concat("a", "b", array3);
console.log(conValores); // [1, 2, 3, "a", "b", 7, 8]

En JavaScript moderno, el operador spread (...) a menudo se usa como alternativa a concat():

const combinado = [...array1, ...array2, ...array3];
console.log(combinado); // [1, 2, 3, 4, 5, 6, 7, 8]

Métodos para modificar el array original

Como hemos visto, algunos métodos (sort(), reverse(), splice()) modifican el array original. Esto se conoce como "mutación". Otros métodos (slice(), concat()) no modifican el original, sino que crean uno nuevo.

La elección entre métodos que mutan o no depende del contexto:

// Ejemplo comparativo
const original = [1, 2, 3, 4, 5];

// Método que muta (modifica el original)
original.reverse();
console.log(original); // [5, 4, 3, 2, 1]

// Restablecer para la siguiente demo
const original2 = [1, 2, 3, 4, 5];

// Enfoque que no muta (patrón funcional)
const invertido = original2.slice().reverse();
// o con ES6: const invertido = [...original2].reverse();
console.log(invertido); // [5, 4, 3, 2, 1]
console.log(original2); // [1, 2, 3, 4, 5] - no cambia

Resumen de métodos que modifican el array original:

  • push(), pop(), shift(), unshift(): añaden o eliminan elementos
  • sort(), reverse(): reordenan elementos
  • splice(): añade, elimina o reemplaza elementos

Métodos que no modifican el array original:

  • slice(), concat(): crean nuevos arrays
  • join(): crea una cadena
  • indexOf(), lastIndexOf(), includes(), find(), findIndex(): búsqueda

Métodos para generar strings

toString()

El método toString() convierte un array a una cadena con los elementos separados por comas:

const numeros = [1, 2, 3, 4, 5];
console.log(numeros.toString()); // "1,2,3,4,5"

const mixto = [1, "hola", true, { a: 1 }];
console.log(mixto.toString()); // "1,hola,true,[object Object]"

join()

Como vimos anteriormente, join() es más flexible que toString() ya que permite especificar el separador:

const elementos = ["Fuego", "Agua", "Tierra", "Aire"];
console.log(elementos.toString()); // "Fuego,Agua,Tierra,Aire"
console.log(elementos.join(" | ")); // "Fuego | Agua | Tierra | Aire"

Comprobación de arrays

Array.isArray()

El método estático Array.isArray() permite verificar si un valor es un array:

console.log(Array.isArray([1, 2, 3])); // true
console.log(Array.isArray("texto")); // false
console.log(Array.isArray({ a: 1 })); // false
console.log(Array.isArray(null)); // false
console.log(Array.isArray()); // false

// Funciona correctamente incluso con arrays de diferentes contextos
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const arrayDeOtroContexto = iframe.contentWindow.Array([1,2,3]);
console.log(Array.isArray(arrayDeOtroContexto)); // true

Este método es más fiable que usar el operador instanceof:

const arr = [1, 2, 3];
console.log(arr instanceof Array); // true

// Pero instanceof puede fallar en ciertos casos
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const arrayDeOtroContexto = iframe.contentWindow.Array([1,2,3]);
console.log(arrayDeOtroContexto instanceof Array); // false

Ejemplos prácticos de uso

Filtrar duplicados de un array

const numeros = [1, 2, 2, 3, 4, 4, 5];

// Usando filter con indexOf
const unicos1 = numeros.filter((valor, indice, self) => {
    return self.indexOf(valor) === indice;
});
console.log(unicos1); // [1, 2, 3, 4, 5]

// Usando Set (ES6)
const unicos2 = [...new Set(numeros)];
console.log(unicos2); // [1, 2, 3, 4, 5]

Encontrar el valor máximo/mínimo

const precios = [29.99, 10.50, 25.30, 42.75, 15.20];

// Usando Math.max/min con spread operator
const maximo = Math.max(...precios);
const minimo = Math.min(...precios);

console.log(`Precio máximo: ${maximo}`); // "Precio máximo: 42.75"
console.log(`Precio mínimo: ${minimo}`); // "Precio mínimo: 10.5"

// Usando reduce
const maximoReduce = precios.reduce((max, precio) => {
    return precio > max ? precio : max;
}, precios[0]);

const minimoReduce = precios.reduce((min, precio) => {
    return precio < min ? precio : min;
}, precios[0]);

console.log(maximoReduce); // 42.75
console.log(minimoReduce); // 10.5

Aplanar un array anidado

// En ES6
function aplanar(arr) {
    return arr.reduce((acumulado, actual) => {
        return acumulado.concat(Array.isArray(actual) ? aplanar(actual) : actual);
    }, []);
}

const anidado = [1, [2, 3], [4, [5, 6]]];
console.log(aplanar(anidado)); // [1, 2, 3, 4, 5, 6]

// En ES2019+ (método nativo)
console.log(anidado.flat(Infinity)); // [1, 2, 3, 4, 5, 6]

Agrupar elementos por propiedad

const estudiantes = [
    { nombre: "Ana", curso: "JavaScript" },
    { nombre: "Luis", curso: "Python" },
    { nombre: "Carlos", curso: "JavaScript" },
    { nombre: "Elena", curso: "Python" },
    { nombre: "Miguel", curso: "HTML" }
];

// Agrupar por curso
const porCurso = estudiantes.reduce((grupos, estudiante) => {
    const curso = estudiante.curso;
    
    if (!grupos[curso]) {
        grupos[curso] = [];
    }
    
    grupos[curso].push(estudiante.nombre);
    return grupos;
}, {});

console.log(porCurso);
// {
//   JavaScript: ["Ana", "Carlos"],
//   Python: ["Luis", "Elena"],
//   HTML: ["Miguel"]
// }

Resumen

Los arrays en JavaScript vienen equipados con una amplia variedad de métodos que nos permiten realizar operaciones comunes de manera sencilla y expresiva. Entre los más importantes destacan:

  • Métodos para añadir/eliminar elementos: push(), pop(), shift(), unshift()
  • Métodos de ordenación y manipulación: sort(), reverse(), splice()
  • Métodos de búsqueda: indexOf(), lastIndexOf(), includes(), find(), findIndex()
  • Métodos de transformación: join(), slice(), concat()
  • Métodos para generar strings: toString(), join()
  • Comprobación de arrays: Array.isArray()

Es importante distinguir entre métodos que modifican el array original y métodos que crean un nuevo array sin modificar el original. Esta distinción es crucial en programación funcional y cuando trabajamos con frameworks reactivos.

Estos métodos nos permiten escribir código más limpio, expresivo y mantenible, evitando tener que implementar funcionalidades comunes desde cero. Dominarlos es un paso fundamental para convertirse en un desarrollador JavaScript eficiente.

En el próximo artículo, exploraremos diferentes técnicas para iterar sobre arrays, incluyendo bucles tradicionales y métodos funcionales como forEach(), map(), filter() y reduce(), que nos permitirán procesar los datos de nuestros arrays de forma aún más potente y declarativa.