reduce just [recursively] combines a data structure into a new value: that value can be anything.
So for example, reimplementing some of the JS array methods (and adding some other common ones):
The normal example, using it to take an array of numbers and sum them, returning a single value: sum([1,2,3,4]) returns 10
function sum(arr) {
  return reduce((a,b) => a + b, 0);
}
reverse returns a reversed version of the input array (non-mutating version of Array.prototype.reverse). So reverse([1,2,3,4]) returns [4,3,2,1].
function reverse(arr) {
  return arr.reduce((acc, v) => [v, ... acc], []);
}
Do the same as Array.prototype.map - so map([1,2,3,4], (x) => x ** 2) returns [1,4,9,16].
function map(arr, fn) {
  return arr.reduce((acc, v) => {
    return  acc.concat(fn(v));
  }, []);
}
Flattens an array of arrays to a single array, same as Array.prototype.flat - so  flatten([[1],[2],[3],[4]]) returns [1,2,3,4].
function flatten(arr) {
  return reduce((acc, arr) => [...acc, ...arr], [])
}
That only works for one level of nesting, so could take an array of arrays of any depth and flatten to one array: so flattenDeep([1,[2,[3,4]]]) returns [1,2,3,4].
function flattenDeep(arr) {
  return arr.reduce((acc, v) => {
    if (Array.isArray(v)) {
      return acc.concat(flatten(v));
    } else {
      return acc.concat(v);
    }
  }, []);
}
Joins an array into a string with a given joining string - same as Array.prototype.join, so join([1,2,3,4], ' ') returns '1 2 3 4'.
function join(arr, joiner = ',') {
  return arr.reduce((acc, v, index) => {
    if (index == 0) {
      return `${v}`
    } else {
      return `${acc}${joiner}${v}`;
    }
  }, '');
}
Given an array, returns an array with an item inserted between each of the original values, so intersperse([1,2,3,4], 'hi') returns[1, 'hi', 2, 'hi', 3, 'hi', 4].
function intersperse(arr, item) {
  return arr.reduce((acc, v, index) => {
    if (index == 0) {
      return [v]
    } else {
      return acc.concat([item, v]);
    }
  }, []);
}
Filter and map on the same array, first function you pass is the filter, then anything that gets through that gets mapped - so filterMap([1,2,3,4], (x) => x % 2 === 0, (x) => x ** 2) returns [4, 16]
function filterMap(arr, filter, mapper) {
  return arr.reduce((acc, v) => {
    if (filter(v)) {
      return  acc.concat(mapper(v));
    } else {
      return acc;
    }
  }, []);
}