Métodos de array en JavaScript III: sort, at(), includes y métodos de búsqueda

JavaScript tiene métodos de array menos conocidos pero muy útiles para tareas concretas: ordenar con criterio personalizado, acceder al último elemento de forma limpia, comprobar existencia incluso con NaN, crear arrays desde cualquier iterable y gestionar porciones de array. Conocerlos evita reinventar la rueda.

sort(): ordenar con función comparadora

sort() sin argumentos convierte los elementos a string y los ordena lexicográficamente, lo que da resultados incorrectos con números. Siempre hay que pasar una función comparadora:

// sort() sin comparadora: orden lexicográfico (incorrecto para números)
const nums = [10, 1, 21, 2, 100];
console.log(nums.sort());  // [1, 10, 100, 2, 21] — INCORRECTO

// Con función comparadora:
// fn(a, b) < 0: a va antes; > 0: b va antes; = 0: mismo orden
nums.sort((a, b) => a - b);  // ascendente
console.log(nums);  // [1, 2, 10, 21, 100]

nums.sort((a, b) => b - a);  // descendente
console.log(nums);  // [100, 21, 10, 2, 1]

// Ordenar objetos por propiedad
const productos = [
  { nombre: 'Monitor', precio: 350 },
  { nombre: 'Teclado', precio: 89 },
  { nombre: 'Ratón', precio: 45 }
];

productos.sort((a, b) => a.precio - b.precio);
console.log(productos.map(p => p.nombre));
// ['Ratón', 'Teclado', 'Monitor']

// Ordenar strings: localeCompare para soporte de acentos y ñ
const nombres = ['Ángel', 'Ana', 'Álvaro', 'Beatriz', 'Óscar'];
nombres.sort((a, b) => a.localeCompare(b, 'es'));
console.log(nombres);
// ['Álvaro', 'Ana', 'Ángel', 'Beatriz', 'Óscar']

at(): acceso con índice negativo

El método at(índice) acepta índices negativos para contar desde el final, igual que Python. Es más claro que arr[arr.length - 1]:

const letras = ['a', 'b', 'c', 'd', 'e'];

console.log(letras.at(0));   // 'a' — primer elemento
console.log(letras.at(-1));  // 'e' — último elemento
console.log(letras.at(-2));  // 'd' — penúltimo
console.log(letras.at(10));  // undefined (fuera de rango)

// Comparación con el acceso clásico:
const ultimo = letras[letras.length - 1];  // 'e' (verboso)
const ultimoAt = letras.at(-1);             // 'e' (limpio)

// También funciona con strings y TypedArrays:
const texto = 'JavaScript';
console.log(texto.at(-1));  // 't'
console.log(texto.at(0));   // 'J'

includes() vs indexOf(): cuándo importa la diferencia

includes(valor) devuelve un booleano y maneja correctamente NaN. indexOf(valor) usa comparación estricta y no encuentra NaN:

const valores = [1, 2, NaN, 4, 5];

// includes: correcto con NaN
console.log(valores.includes(NaN));    // true
console.log(valores.includes(3));      // false
console.log(valores.includes(1, 2));   // false (busca desde índice 2)

// indexOf: no encuentra NaN
console.log(valores.indexOf(NaN));     // -1 (incorrecto)
console.log(valores.indexOf(2));       // 1

// Cuándo usar indexOf: cuando necesitas la posición
const idx = valores.indexOf(4);
if (idx !== -1) {
  valores.splice(idx, 1);  // eliminar elemento por valor
}

// Cuándo usar includes: cuando solo necesitas saber si existe
const permitidos = ['admin', 'editor', 'viewer'];
if (permitidos.includes(rolUsuario)) {
  // acceso permitido
}

Array.from(): crear arrays desde cualquier cosa

Array.from(iterable, mapFn) convierte cualquier iterable o array-like en un array real, con una función de transformación opcional:

// Desde un Set (eliminar duplicados)
const unicos = Array.from(new Set([1, 2, 2, 3, 3, 4]));
console.log(unicos);  // [1, 2, 3, 4]

// Desde un string
const letras = Array.from('hola');
console.log(letras);  // ['h', 'o', 'l', 'a']

// Desde NodeList (acceso DOM)
const parrafos = Array.from(document.querySelectorAll('p'));
parrafos.forEach(p => console.log(p.textContent));

// Crear array de N elementos con transformación
const cuadrados = Array.from({ length: 5 }, (_, i) => (i + 1) ** 2);
console.log(cuadrados);  // [1, 4, 9, 16, 25]

const rango = Array.from({ length: 10 }, (_, i) => i);
console.log(rango);  // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

splice() vs slice(): la diferencia que más confunde

splice() modifica el array original; slice() devuelve una copia sin modificar el original:

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

// slice(inicio, fin): extrae sin modificar
const porcion = arr.slice(1, 3);
console.log(porcion);  // [2, 3]
console.log(arr);      // [1, 2, 3, 4, 5] — sin cambios

// slice con negativos
console.log(arr.slice(-2));    // [4, 5]
console.log(arr.slice(1, -1)); // [2, 3, 4]

// splice(inicio, eliminar, ...insertar): modifica el original
const arr2 = [1, 2, 3, 4, 5];
const eliminados = arr2.splice(1, 2, 'a', 'b', 'c');
console.log(eliminados);  // [2, 3] (lo que se eliminó)
console.log(arr2);        // [1, 'a', 'b', 'c', 4, 5]

// splice para eliminar un elemento concreto
const lista = ['rojo', 'verde', 'azul'];
const idx = lista.indexOf('verde');
if (idx !== -1) lista.splice(idx, 1);
console.log(lista);  // ['rojo', 'azul']

La regla mnemotécnica: slice no cambia el original (como hacer una foto); splice lo destruye y reconstruye (corta y pega).

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP