TL; DR, establece el valor inicial
Usando la desestructuración
arr.reduce( ( sum, { x } ) => sum + x , 0)
Sin desestructuración
arr.reduce( ( sum , cur ) => sum + cur.x , 0)
Con mecanografiado
arr.reduce( ( sum, { x } : { x: number } ) => sum + x , 0)
Probemos el método de desestructuración:
const arr = [ { x: 1 }, { x: 2 }, { x: 4 } ]
const result = arr.reduce( ( sum, { x } ) => sum + x , 0)
console.log( result ) // 7
La clave para esto es establecer el valor inicial. El valor de retorno se convierte en el primer parámetro de la siguiente iteración.
La técnica utilizada en la respuesta superior no es idiomática
La respuesta aceptada propone NO pasar el valor "opcional". Esto está mal, ya que la forma idiomática es que siempre se incluya el segundo parámetro . ¿Por qué? Tres razones:
1. Peligroso
: no pasar el valor inicial es peligroso y puede crear efectos secundarios y mutaciones si la función de devolución de llamada es descuidada.
Mirad
const badCallback = (a,i) => Object.assign(a,i)
const foo = [ { a: 1 }, { b: 2 }, { c: 3 } ]
const bar = foo.reduce( badCallback ) // bad use of Object.assign
// Look, we've tampered with the original array
foo // [ { a: 1, b: 2, c: 3 }, { b: 2 }, { c: 3 } ]
Sin embargo, si lo hubiéramos hecho de esta manera, con el valor inicial:
const bar = foo.reduce( badCallback, {})
// foo is still OK
foo // { a: 1, b: 2, c: 3 }
Para el registro, a menos que tenga la intención de mutar el objeto original, establezca el primer parámetro Object.assign
en un objeto vacío. De esta manera: Object.assign({}, a, b, c)
.
2 - Mejor inferencia de
tipos: al usar una herramienta como TypeScript o un editor como VS Code, obtienes el beneficio de decirle al compilador la inicial y puede detectar errores si lo estás haciendo mal. Si no establece el valor inicial, en muchas situaciones podría no ser capaz de adivinar y podría terminar con errores de tiempo de ejecución espeluznantes.
3 - Respeta a los Functores
- JavaScript brilla mejor cuando se desata su hijo funcional interno. En el mundo funcional, hay un estándar sobre cómo "doblar" o reduce
una matriz. Cuando dobla o aplica un catamorfismo a la matriz, toma los valores de esa matriz para construir un nuevo tipo. Debe comunicar el tipo resultante; debe hacerlo incluso si el tipo final es el de los valores de la matriz, otra matriz o cualquier otro tipo.
Pensemos de otra manera. En JavaScript, las funciones se pueden pasar como datos, así es como funcionan las devoluciones de llamada, ¿cuál es el resultado del siguiente código?
[1,2,3].reduce(callback)
¿Devolverá un número? ¿Un objeto? Esto lo hace más claro
[1,2,3].reduce(callback,0)
Lea más sobre las especificaciones de programación funcional aquí: https://github.com/fantasyland/fantasy-land#foldable
Un poco más de fondo
El reduce
método toma dos parámetros,
Array.prototype.reduce( callback, initialItem )
La callback
función toma los siguientes parámetros
(accumulator, itemInArray, indexInArray, entireArray) => { /* do stuff */ }
Para la primera iteración,
Si initialItem
se proporciona, la reduce
función pasa initialItem
como el accumulator
y el primer elemento de la matriz como itemInArray
.
Si initialItem
se no se proporciona, la reduce
función pasa el primer elemento en la matriz como el initialItem
y el segundo elemento de la matriz como itemInArray
la que puede ser confuso comportamiento.
Enseño y recomiendo siempre establecer el valor inicial de reducir.
Puede consultar la documentación en:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
¡Espero que esto ayude!
arr.reduce(function(a,b){return a + b})
al segundo ejemplo.