Array.prototype.reduceRight()

Identical to reduce in every respect except direction: it starts at the last element and works towards the first. For a sum that changes nothing, and for anything order-dependent it changes everything.

Array methodES5 (2009)Live demo
Common call
items.reduceRight((acc, x) => acc.concat(x), [])
Returns
a single value, folded from the right
Replaces
items.slice().reverse().reduce(...) — one fewer copy
Watch out
for a sum or a product it is just reduce with extra confusion
array.reduceRight(callback[, initialValue])
→ any

Demo

Live evaluation
Try:
Inputs
itemsstring[]strings, comma separated
Output
['a', 'b', 'c'].reduceRight((a, b) => a + b)
'cba'

String concatenation makes the direction visible: ['a','b','c'] folds to 'cba', where plain reduce gives 'abc'. That is the whole difference. The single-element case returns that element without ever calling the callback, because with no initial value the last element IS the seed and there is nothing left to fold into it. The empty case throws the same TypeError reduce does, for the same reason — no seed, and no element to borrow one from.

Parameters

NameTypeRequiredDescription
callbackFunctionyesCalled as callback(accumulator, element, index, array). The index still reports the real position, so it counts DOWN.
initialValueanyno (last element)Starting accumulator. Omitted, the LAST element is used and iteration starts at the second-to-last — so an empty array throws.

Return value

any — Whatever the callback returned on the final iteration — which here is the one at index 0. With an initialValue and an empty array, that value comes straight back.

Common patterns

Compose functions
The classic use. compose(f, g, h)(x) is f(g(h(x))) — the LAST function listed runs first.
const compose = (...fns) => x =>
  fns.reduceRight((acc, f) => f(acc), x);
Flatten one level, back to front
Order is reversed as a side effect of the direction.
const flat = nested.reduceRight((acc, x) => acc.concat(x), []);
Build a nested structure from the inside out
Wrapping layers where the last element ends up innermost.
const wrapped = layers.reduceRight((inner, L) => L(inner), core);

Examples

1. Concatenation reverses
['a','b','c'].reduceRight((a, b) => a + b)
Returns
'cba'
2. reduce for contrast
['a','b','c'].reduce((a, b) => a + b)
Returns
'abc'
3. Subtraction differs
[1, 2, 3].reduceRight((a, b) => a - b)
Returns
0
4. reduce again
[1, 2, 3].reduce((a, b) => a - b)
Returns
-4
5. A sum is identical
[1, 2, 3].reduceRight((a, b) => a + b, 0)
Returns
6
6. Empty, no initial
[].reduceRight((a, b) => a + b)
Returns
TypeError: Reduce of empty array with no initial value

Pitfalls

1. Reaching for it when the operation is commutative
Summing, multiplying, counting, taking a maximum — none of these care about direction, so reduceRight produces exactly what reduce would while making the reader stop and work out whether it matters. Use it only when the order genuinely changes the answer.
No difference, more thought
[1, 2, 3].reduceRight((a, b) => a + b, 0)
6
Just reduce
[1, 2, 3].reduce((a, b) => a + b, 0)
6
2. The accumulator is still the FIRST parameter
Direction changes, parameter order does not. The callback is always (accumulator, element) — not (element, accumulator) — so a subtraction reads as acc - element even though the elements arrive backwards.
Read as element - acc
[1, 2, 3].reduceRight((a, b) => a - b)
0 // 3 - 2 = 1, then 1 - 1 = 0
acc is a, element is b
[1, 2, 3].reduceRight((acc, el) => acc - el)
0
3. Same empty-array TypeError as reduce
Omitting the initial value carries identical risk. reduceRight seeds from the LAST element instead of the first, but an empty array has neither, and the message is word-for-word the same.
Throws on empty
[].reduceRight((a, b) => a + b)
TypeError: Reduce of empty array with no initial value
Always seed it
[].reduceRight((a, b) => a + b, 0)
0
4. reverse() before reduce mutates
The obvious substitute is a trap. reverse reorders the array IN PLACE, so writing items.reverse().reduce(...) silently rearranges the array the caller handed you. reduceRight needs no copy and no mutation.
Mutates the source
items.reverse().reduce(f)
items is now backwards
Or copy first
items.reduceRight(f)
items untouched

When to use

Use it
  • Function composition, where the rightmost function should apply first
  • Folding a non-commutative operation from the end — concatenation, subtraction, division
  • Building nested structures from the innermost layer outwards
  • Anywhere you would otherwise reverse a copy just to reduce it
Reach for something else
  • The operation is commutative → reduce, which reads more plainly
  • You want the array reversed as a value → toReversed
  • One value out per value in → map
  • You only need the last element → at(-1)

Notes

Complexity
O(n) for the iteration, plus whatever the callback costs
Return
The final accumulator; the original array is never modified
CPython impl
V8: Builtins-array-reduce.tq (shared with reduce)
Memory
Only the accumulator — no reversed copy is made
Thread-safe
Single-threaded; mutating the source inside the callback is undefined behaviour for unvisited indices

FAQ

Only when the callback is not commutative — when f(a, b) and f(b, a) disagree. Addition, multiplication and Math.max give identical results either way. Concatenation, subtraction, division and anything that builds an ordered structure do not.

['a','b','c'].reduce((a, b) => a + b);       // 'abc'
['a','b','c'].reduceRight((a, b) => a + b);  // 'cba'

History

ES5
Array.prototype.reduceRight standardised in 2009 alongside reduce.