Pregunta 1Cuando la función de comparación devuelve un valor negativo, ¿qué elemento pone primero sort?
Ordenar y buscar — sort / find / some / every
Aprende sort, que ordena según una función de comparación, toSorted, que conserva el original, find y findIndex, que devuelven una coincidencia, y some y every.
Si ordenas una lista con un bucle for que intercambia elementos, tienes que encargarte tú de las comparaciones y de los intercambios cada vez. Buscar el único elemento que cumple una condición te lleva al mismo tipo de código: un bucle for con un break para salir en cuanto lo encuentras.
En este artículo verás sort, que reordena un array, y find, que busca un elemento que cumple una condición.
Indicar el orden con una función — sort y la función de comparación
Supón que quieres mostrar una lista de productos ordenada del más barato al más caro. Un método de array se encarga de ordenar, pero si solo escribes products.sort(), no se ordena por precio, porque no le has dicho qué debe comparar.
A sort (un método que reordena los elementos de un array) le pasas una función de comparación (una función que recibe 2 elementos y devuelve un número). Si llamas a y b a los 2 elementos que recibe, un valor de retorno negativo pone primero a a y uno positivo pone primero a b. Si devuelves a.price - b.price, obtienes los precios en orden ascendente.
const products = [
{ name: "Mouse inalámbrico", price: 2980 },
{ name: "Batería portátil", price: 4380 },
{ name: "Cable USB-C", price: 980 },
{ name: "Pad para mouse", price: 2980 },
];
// Si la resta es negativa, a va primero; si es positiva, va primero b
products.sort((a, b) => a.price - b.price);
console.log(products.map((item) => item.price).join(", ")); // 980, 2980, 2980, 4380
// Comprueba el orden de los 2 productos con el mismo precio
console.log(products[1].name, products[2].name); // Mouse inalámbrico Pad para mouse
// Si inviertes la resta, obtienes el orden descendente
products.sort((a, b) => b.price - a.price);
console.log(products[0].name); // Batería portátil
sort solo se fija en el signo del número devuelto, así que -2000 y -1 se tratan igual. Si también quieres controlar el orden de los productos con el mismo precio, haz que la función de comparación compare otro valor cuando la diferencia sea 0.
Llamar a sort sin argumentos — la comparación por defecto y toSorted
Supón que quieres ordenar, de menor a mayor, un array con los segundos de permanencia en una página. Si llamas a sort() sin función de comparación, el resultado no sale en orden numérico: 1180 segundos queda antes que 25 segundos.
Sin función de comparación, sort primero convierte los elementos en cadenas y luego las compara carácter por carácter. 1180 se trata como "1180" y 25 como "25", así que el orden lo deciden el 1 y el 2 iniciales. sort reordena el propio array sobre el que se llama, así que si también quieres conservar el orden original, usa toSorted (un método que devuelve un array nuevo ya ordenado).
const viewSeconds = [1180, 980, 25, 4380];
// Sin función de comparación, se comparan como cadenas
console.log(viewSeconds.sort().join(", ")); // 1180, 25, 4380, 980
// Si pasas una función de comparación, se ordenan como números
console.log(viewSeconds.sort((a, b) => a - b).join(", ")); // 25, 980, 1180, 4380
// toSorted devuelve un array nuevo y no cambia el original
const stayTimes = [1180, 980, 25, 4380];
console.log(stayTimes.toSorted((a, b) => a - b).join(", ")); // 25, 980, 1180, 4380
console.log(stayTimes.join(", ")); // 1180, 980, 25, 4380
Una vez convertidos en cadenas, "1180" siempre queda antes que "25", así que pasa una función de comparación cuando ordenes un array de números. El segundo sort del código de arriba vuelve a ordenar viewSeconds, que ya había quedado reordenado por la primera llamada.
sort en la fila de arriba es el propio viewSeconds reordenado. Solo toSorted crea un array nuevo.Los navegadores antiguos no tienen toSorted
toSorted se añadió a la especificación en ES2023, y en los navegadores antiguos que no lo admiten, la línea que lo llama lanza un TypeError. Para que también funcione en esos entornos, llama a sort sobre una copia hecha con la sintaxis spread, como en [...stayTimes].sort((a, b) => a - b).
Obtener el elemento que coincide — find y findIndex
Supón que quieres obtener una reservación a partir de su código. Podrías usar filter, pero devuelve un array, así que tendrías que añadir [0] para leer el primer elemento; y si ninguna reservación coincide, obtienes un array vacío.
find (un método que devuelve el primer elemento que cumple una condición) devuelve el propio elemento: el primero para el que el callback devuelve true. Si lo que quieres es su posición, usa findIndex (un método que devuelve la posición del primer elemento que cumple una condición).
const reservations = [
{ code: "RSV-201", room: "Sala de reuniones A" },
{ code: "RSV-202", room: "Sala de reuniones B" },
{ code: "RSV-203", room: "Sala de reuniones C" },
];
// Devuelve el primer elemento para el que el callback devolvió true
const target = reservations.find((item) => item.code === "RSV-202");
console.log(target.room); // Sala de reuniones B
// Usa findIndex cuando quieras la posición
console.log(reservations.findIndex((item) => item.code === "RSV-202")); // 1
// Cuando ninguna reservación coincide
console.log(reservations.find((item) => item.code === "RSV-999")); // undefined
console.log(reservations.findIndex((item) => item.code === "RSV-999")); // -1
true para el segundo elemento, ya no se llama para el tercero. Cuanto antes esté la coincidencia, menos llamadas se hacen.find devuelve solo el primer elemento que coincide, así que no sirve para reunir todas las coincidencias cuando hay varias. Usa filter, que devuelve un array, cuando las necesites todas, y find cuando te baste con una.
Si no encuentra nada, obtienes undefined
Si lees directamente el valor que devolvió find, como en target.room, y ningún elemento coincidió, se lanza TypeError: Cannot read properties of undefined (reading 'room'). Compruébalo con if (target) antes de leerlo.
Comprobar todo el array con true o false — some y every
Supón que quieres decidir, según las existencias, si todos los artículos de un pedido pueden enviarse juntos. Podrías reunir con filter los artículos agotados y contarlos, pero lo que buscas no es un array, sino una sola respuesta: true o false.
some (un método que devuelve true si al menos un elemento cumple la condición) y every (un método que devuelve true si todos los elementos cumplen la condición) devuelven un booleano, no un elemento. Puedes usarlos directamente como condición de un if.
const orderItems = [
{ name: "Botella recargable", stock: 12 },
{ name: "Jabón de manos", stock: 0 },
{ name: "Esponja de baño", stock: 5 },
];
// true si al menos uno cumple
console.log(orderItems.some((item) => item.stock === 0)); // true
// true solo si todos cumplen
console.log(orderItems.every((item) => item.stock > 0)); // false
// Con un array vacío, some da false y every da true
console.log([].some((item) => item.stock > 0)); // false
console.log([].every((item) => item.stock > 0)); // true
some como every tienen su respuesta en el segundo elemento, que tiene 0 existencias. every termina en cuanto encuentra un elemento que no cumple.Con un array vacío, ningún elemento cumple la condición, así que some da false; y tampoco hay ninguno que no la cumpla, así que every da true. La tabla de abajo resume lo que devuelven los 4 métodos de búsqueda de este artículo.
| Método | Devuelve | Si ningún elemento coincide |
|---|---|---|
| find | El propio primer elemento que coincide | undefined |
| findIndex | La posición del primer elemento que coincide | -1 |
| some | true si al menos uno coincide | false |
| every | true si todos coinciden | false (true con un array vacío) |
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2Si llamas a sort() sobre [1180, 980, 25] sin función de comparación, ¿en qué orden quedan?
Pregunta 3¿Qué método usas para comprobar, con un solo booleano, si todos los productos tienen al menos 1 unidad en existencia?