Métodos de array en JavaScript II: find, findIndex, some, every y flat

Más allá de map, filter y reduce, JavaScript ofrece métodos de array especializados que resuelven tareas concretas de forma más expresiva. Conocer cuál usar en cada situación evita implementaciones manuales innecesarias y bugs sutiles.

find() y findIndex(): buscar el primer elemento

find(fn) devuelve el primer elemento para el que fn devuelve verdadero, o undefined si no lo encuentra. findIndex(fn) devuelve el índice de ese elemento, o -1:

const usuarios = [
  { id: 1, nombre: 'Ana', activo: true },
  { id: 2, nombre: 'Luis', activo: false },
  { id: 3, nombre: 'Sara', activo: true }
];

// find: devuelve el objeto, no solo un valor
const usuarioActivo = usuarios.find(u => u.activo);
console.log(usuarioActivo);  // { id: 1, nombre: 'Ana', activo: true }

const porId = usuarios.find(u => u.id === 2);
console.log(porId?.nombre);  // 'Luis'

const noExiste = usuarios.find(u => u.id === 99);
console.log(noExiste);  // undefined

// findIndex: para obtener posición y poder splice/update
const indice = usuarios.findIndex(u => u.id === 2);
console.log(indice);  // 1

// Diferencia clave con filter:
// find ? primer elemento encontrado (o undefined)
// filter ? todos los elementos que cumplen (o [])
const activos = usuarios.filter(u => u.activo);
console.log(activos.length);  // 2

findLast() y findLastIndex(): buscar desde el final

ES2023 añadió las versiones que recorren el array de atrás hacia adelante:

const logs = [
  { nivel: 'info', msg: 'Inicio' },
  { nivel: 'error', msg: 'Fallo conexión' },
  { nivel: 'info', msg: 'Reintento' },
  { nivel: 'error', msg: 'Timeout' },
  { nivel: 'info', msg: 'OK' }
];

// Último error registrado
const ultimoError = logs.findLast(l => l.nivel === 'error');
console.log(ultimoError.msg);  // 'Timeout'

const indiceUltimoError = logs.findLastIndex(l => l.nivel === 'error');
console.log(indiceUltimoError);  // 3

some() y every(): comprobar condiciones

some(fn) devuelve true si al menos un elemento cumple la condición. every(fn) devuelve true solo si todos la cumplen. Ambos hacen cortocircuito:

const edades = [22, 17, 30, 15, 25];

// ¿Hay algún menor?
const hayMenores = edades.some(edad => edad < 18);
console.log(hayMenores);  // true

// ¿Son todos mayores de edad?
const todosMayores = edades.every(edad => edad >= 18);
console.log(todosMayores);  // false

// Casos con array vacío (importante para lógica booleana):
[].some(x => x > 0);   // false (vacío ? ninguno cumple)
[].every(x => x > 0);  // true  (vacío ? todos cumplen, vacuamente)

// Ejemplo real: validación de formulario
const campos = [
  { nombre: 'email', valor: '[email protected]', valido: true },
  { nombre: 'pass', valor: '1234', valido: false },
  { nombre: 'nombre', valor: 'Ana', valido: true }
];

const formularioValido = campos.every(c => c.valido);
const hayErrores = campos.some(c => !c.valido);

console.log(formularioValido);  // false
console.log(hayErrores);        // true

flat() y flatMap(): aplanar arrays anidados

flat(profundidad) crea un nuevo array con los sub-arrays aplanados hasta la profundidad indicada. flatMap(fn) es equivalente a map(fn).flat(1) pero más eficiente:

// flat(): aplanar arrays anidados
const anidado = [1, [2, 3], [4, [5, 6]]];
console.log(anidado.flat());     // [1, 2, 3, 4, [5, 6]] — profundidad 1
console.log(anidado.flat(2));    // [1, 2, 3, 4, 5, 6]
console.log(anidado.flat(Infinity));  // siempre aplanado del todo

// Eliminar huecos (slots vacíos) en arrays
const conHuecos = [1, , 3, , 5];
console.log(conHuecos.flat());  // [1, 3, 5]

// flatMap(): mapear y aplanar un nivel
const frases = ['Hola mundo', 'JavaScript es genial'];
const palabras = frases.flatMap(f => f.split(' '));
console.log(palabras);  // ['Hola', 'mundo', 'JavaScript', 'es', 'genial']

// Caso real: expandir etiquetas de artículos
const articulos = [
  { titulo: 'JS Moderno', etiquetas: ['js', 'es6', 'web'] },
  { titulo: 'Node.js', etiquetas: ['js', 'node', 'backend'] }
];

const todasEtiquetas = articulos.flatMap(a => a.etiquetas);
console.log([...new Set(todasEtiquetas)]);
// ['js', 'es6', 'web', 'node', 'backend']

El TypeError más frecuente

Llamar a estos métodos sobre un valor que no es array es el error más común. Suele ocurrir al trabajar con datos de API que no siempre devuelven lo esperado:

// Si la API devuelve null en lugar de array:
const datos = null;
datos.find(x => x.id === 1);  // TypeError: Cannot read properties of null

// Protección básica:
const resultado = (datos ?? []).find(x => x.id === 1);

// O verificar antes:
if (Array.isArray(datos)) {
  const item = datos.find(x => x.id === 1);
}

La elección entre estos métodos depende de lo que necesites: usa find cuando buscas un elemento, some cuando solo necesitas saber si existe, every para validaciones globales y flatMap cuando cada elemento del array puede generar cero o más elementos en el resultado.

COMPARTE ESTE ARTÍCULO

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