Método Javascript reduce(): array index, valor inicial, object, sum async, break
El método Array.prototype.reduce()
en JavaScript es uno de los métodos de array más utilizados,
Es un buen ejemplo de la programación funcional de JavaScript.
Cuando aprendes a programar por primera vez, eres introducido a la programación procedimental y orientada a objetos,
El método reduce()
no siempre es fácil de entender intuitivamente.
Así que, en este post, voy a echar un vistazo desde la programación funcional hasta varios ejemplos del mundo real para entender el método reduce()
.
1. Programación Funcional JavaScript en pocas palabras
La programación funcional es un paradigma de programación que se refiere a una técnica para diseñar el comportamiento de un programa basado en funciones en el sentido matemático.
En la programación funcional, mientras pongas los mismos valores en una función, siempre deberías obtener el mismo resultado. Una función que sigue este principio se llama función pura y no debería cambiar ningún valor de estado en su comportamiento. Si lo hace, se llama efecto secundario, y la programación funcional pretende minimizarlos.
También enfatiza la inmutabilidad del estado y los datos, así que en lugar de cambiar los valores de una estructura de datos
diseñamos nuestros programas para crear nuevas estructuras de datos.
Esto significa que si quieres cambiar el array [1, 2, 3]
a [1, 2, 4]
, creas un nuevo array [1, 2, 4]
.
Los programas diseñados de esta forma tienen grandes ventajas para cosas como la programación concurrente, en la que se accede a los datos simultáneamente.
Por último, JavaScript trata a las funciones como ciudadanos de primera clase - objetos que se pueden utilizar en cualquier lugar: variables, parámetros, valores de retorno, etc, Es un lenguaje ideal para la programación funcional. Como resultado, muchos desarrolladores de JS utilizan la programación funcional para escribir código mantenible y fiable.
Las funciones que se definen como funcionales son
const add = (a, b) => a + b;
const result = add(1, 2); // Output is always 3
1.1. Por qué el método reduce() es importante para la programación funcional
El método reduce()
se adhiere a los principios de la programación funcional en JavaScript porque realiza operaciones en un array sin modificar el array existente.
Esto es especialmente cierto cuando estás reduciendo un array a un único valor o acumulando resultados basados en los elementos del array, porque no tienes que gestionar los valores acumulados fuera de la función.
Además, no tiene efectos secundarios.
Como resultado, es un método esencial para escribir código más limpio y mantenible.
2. Entendiendo el método reduce(): inicialización, índice y acumulador
El método reduce()
es un método de array que recorre un array y ejecuta la función proporcionada (reducer) para cada elemento del array para producir un único valor de salida.
La sintaxis básica es
array.reduce(reducerFunction, initialValue);
// reducerFunction
array.reduce(((accumulator, currentValue, currentIndex, array) => returnValue), initialValue);
El initialValue
es el valor inicial que se sumará al valor de retorno de la reducerFunction
.
Utilice 0
para obtener la suma de números, ""
para obtener la cadena final, etc.
El reducerFunction
es una función de devolución de llamada que toma cuatro parámetros.
- accumulator (
accumulator
) - acumula el valor de retorno de aplicar la función a todos los elementos hasta el índice anterior. - currentValue (
currentValue
) - El valor del elemento al que se aplica actualmente la función. - index (
currentIndex
) - El índice de la matriz del elemento actual (opcional). - array (
array
) - Una referencia a la propia matriz (opcional).
Veamos un ejemplo sencillo para ver qué valores tendrá cada parámetro.
const numbers = [ 1, 2, 3 ]
numbers.reduce((accumulator, currentValue, currentIndex, array) => {
console.log(`accumulator: ${accumulator}, currentValue: ${currentValue}, currentIndex: ${currentIndex}, array: ${array} `)
return accumulator + currentValue
}, 0);
// Output:
// accumulator: 0, currentValue: 1, currentIndex: 0, array: 1,2,3
// accumulator: 1, currentValue: 2, currentIndex: 1, array: 1,2,3
// accumulator: 3, currentValue: 3, currentIndex: 2, array: 1,2,3
// 6
En la primera llamada a la función reductora con índice 0
, el acumulador tiene un valor inicial de 0
.
La función reductora añade el valor actual 1
al valor del acumulador y lo devuelve, que se convierte en el nuevo valor del acumulador.
Este proceso se repite hasta que el resultado final de la función reduce()
devuelve el valor final del acumulador, 6
.
En otras palabras, para descomprimir el comportamiento del ejemplo anterior, se vería así
const numbers = [ 1, 2, 3 ]
const reducerFunction = element => element
const returnValue = reducerFunction(numbers[0]) + reducerFunction(numbers[1]) + reducerFunction(numbers[2])
console.log(returnValue)
// Output: 6
2.1. Cuidado con las palabras clave break y continue
La mayoría de los métodos de array, incluyendo la función reduce()
, no soportan las palabras clave break,
continue
que manipulan las operaciones transversales.
Si no desea hacer nada con el elemento actual, como utilizar la palabra clave continue
, puede utilizar una sentencia condicional para devolver el valor acumulado tal cual.
En el ejemplo siguiente, pasamos por 3
sin acumular.
const numbers = [ 1, 2, 3 ]
const reducerFunction = (accumulator, element) => {
console.log(`누산기: ${accumulator}, 현재값: ${element}`)
if (element === 3) {
return accumulator
}
return accumulator + element
}
numbers.reduce(reducerFunction, 0)
// Output: 3
3. Cómo utilizarlo para manipular objetos
El método reduce()
también es útil para acceder a las propiedades de un objeto y realizar diversas operaciones sobre ellas.
Puedes acceder a las propiedades del objeto directamente o utilizar un método ayudante como Object.entries()
.
Veámoslos uno a uno.
const people = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 25 },
{ name: 'David', age: 30 }
];
const groupedByAge = people.reduce((accumulator, currentValue) => {
const ageGroup = currentValue.age;
accumulator[ageGroup] = accumulator[ageGroup] || [];
accumulator[ageGroup].push(currentValue);
return accumulator;
}, {});
console.log(groupedByAge);
// Output:
// {
// '25': [
// { name: 'Alice', age: 25 },
// { name: 'Charlie', age: 25 }
// ],
// '30': [
// { name: 'Bob', age: 30 },
// { name: 'David', age: 30 }
// ]
// }
El ejemplo anterior accedía a la propiedad age
de un objeto y realizaba una tarea para clasificar los objetos en dos grupos en función de su edad.
const grades = {
math: 90,
science: 80,
history: 85,
english: 95
};
const totalScore = Object.entries(grades).reduce((accumulator, [subject, score]) => {
return accumulator + score;
}, 0);
console.log(totalScore); // Output: 350
Si necesita manipular múltiples valores de un único objeto, puede utilizar el método Objext.entries()
.
Este método manipula las propiedades del objeto y los valores de las propiedades como un único array, como se muestra arriba.
Esto nos permite usar la función reduce()
en objetos también, y se ve así,
Las asignaciones desestructuradas, como [subject, score]
, pueden usarse para escribir código más conciso.
4. Ejemplos de aplicaciones reales como la eliminación de duplicados
En la sección Función JS filter() - 3. Deduplicación con filter(), también vimos la técnica de deduplicación como ejemplo de código.
Con la función reduce()
, también puedes escribir fácilmente código para eliminar elementos duplicados de un array.
Empecemos con el código.
const array = [1, 2, 3, 2, 4, 3, 5, 1];
const uniqueArray = array.reduce((accumulator, element) => {
if (!accumulator.includes(element)) {
accumulator.push(element);
}
return accumulator;
}, []);
console.log(uniqueArray);
// Output: [1, 2, 3, 4, 5]
El código anterior establece el valor inicial a un array vacío []
y luego añade un nuevo elemento a él si el elemento actual no existe en el array accumulator{js}
.
Utiliza el método Array.includes()
para determinar la inclusión.
Compara esto con el método
String.includes()
utilizado en la sección Función JS filter() - 4. Definiendo funciones callback con includes().
Puedes ver que el array de resultados devuelto por la función reduce
sólo saca elementos no duplicados.
5. Uso de funciones async callback
Hemos visto cómo utilizar funciones de callback asíncronas en métodos array en JS map() method - 6. Async callback: Asynchronous callback functions.
El método map()
, junto con el método Promise.all()
, nos permitió escribir código que funcionaba de forma asíncrona + concurrente.
Sin embargo, el método reducer
no puede utilizarse con funciones callback asíncronas porque no hay forma de soportar el comportamiento asíncrono.
Para evitar esto, tenemos que definir nuestra propia función reduce personalizada que funcione de forma asíncrona utilizando la palabra clave async await
y un objeto Promise
.
Empecemos con el código de ejemplo.
const array = [1, 2, 3, 4, 5];
const asyncReduce = async (array, callback, initialValue) => {
let accumulator = initialValue;
for (const element of array) {
accumulator = await callback(accumulator, element);
}
return accumulator;
};
const sumAsync = async (a, b) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(a + b);
}, 1000);
});
};
const calculateSum = async () => {
const sum = await asyncReduce(array, sumAsync, 0);
console.log(sum);
};
calculateSum();
// Output: 15
La función asyncReduce()
del ejemplo recorre el array a través de la sintaxis for of
, llama a la función de callback asíncrona, y await
para que se completen todas las operaciones.
La función de callback asíncrona arbitraria sumAsync()
espera un segundo y devuelve el resultado de la suma.
Finalmente, la función calculateSum()
sirve como función principal que ejecuta la función asyncReduce()
.
Si ejecutas el código, al cabo de cierto tiempo obtendrás la suma de todos los números, 15
.
6. Conclusión
El método reduce()
de JavaScript es una herramienta potente y versátil para la programación funcional.
Te permite realizar operaciones sobre arrays manteniendo principios como la inmutabilidad y la simplicidad.
Utilízalo sabiamente junto con otros métodos de arrays, y asegúrate de que cuando escribas tu código, sea intuitivo y legible.
