Разбор работы reduce

Добрый день, уважаемые форумчане! Прохожу reduce. Возникли некоторые вопросы по теории, прошу вас о помощи! Имеется задача. Насколько я понял, она считает количество детей в дереве:

const reduce = (f, tree, acc) => {
  const [, children] = tree;
  const newAcc = f(acc);

  if (!children) {
    return newAcc;
  }
  return children.reduce((iAcc, n) => reduce(f, n, iAcc), newAcc);
};

const tree = ['A', [
  ['B', [['E'], ['F']]],
  ['C'],
  ['D', [['G'], ['J']]],
]];

reduce((acc) => acc + 1, tree, 0); // 8

Вопрос у меня к самому подсчёту, а именно к этой строчке: -> const newAcc = f(acc);
Мне не совсем понятно, как в переменную newAcc попадает число после работы этой функции: (acc) => acc + 1, tree, 0
Что именно меня смущает?
мне была бы понятно такая функция: (acc) => acc += 1; Но зачем здесь дополнительные параметры tree и 0? Какую роль они играют? … И как сюда: const reduce = (f, tree, acc) => { в acc, попадает с каждым вызовом новое число? Объясните пожалуйста. Правда, очень хочется разобраться!

Но зачем здесь дополнительные параметры tree и 0?

0 - начальное значение, с которого начинается отсчет
tree - начальное (можно сказать, голова) дерево
И начиная с них ты перебираешь все дерево. При этом с acc каждый раз происходит то, что ты указал в начальной функции (acc) => acc + 1 , а tree превращается в children.

Смотрите! У Мы записали, предположим, единицу в константу newAcc. Всё, она там. Спускаемся с ней вниз… Как она попадает в acc? Ведь она должна попасть в acc этой строки, как я понимаю -> const reduce = (f, tree, acc) => { ?

Мы же вызываем нативный reduce массива тут:
return children.reduce((iAcc, n) => reduce(f, n, iAcc), newAcc);

children.reduce - reduce массива, который обходит все текущие элементы первого уровня.
И плюс мы рекурсивно вызываем самописный reduce(f, n, iAcc), в который передаем не newAcc, а аккумулированный iAcc

Попробуй разобрать задачу с меньшим уровнем вложенности:

const reduce = (addOneFunc, tree, passedAcc) => { // func, [A, [[B], [C], [D]]], 0
  const [, children] = tree; // children = [[B], [C], [D]]
  const passedAccPlusOne = addOneFunc(passedAcc); // 0+1

  if (!children) { // exit condition, если нет детей
    return passedAccPlusOne;
  }
  return children.reduce((iAcc, n) => reduce(addOneFunc, n, iAcc), passedAccPlusOne);
  // iAcc - накапливается по мере обхода детей
  // addOneFunc - не меняется
  // passedAccPlusOne - другая при каждом вызове самописного reduce
};

const tree = ['A', [['B'], ['C'], ['D']]];

reduce((acc) => acc + 1, tree, 0);

" в который передаем не newAcc, а аккумулированный iAcc" - тогда зачем мы записываем единицу в newAcc? Где мы единицу передаём в iAcc? Как она туда попадает?

Вот здесь:

return children.reduce((iAcc, n) => { return reduce(addOneFunc, n, iAcc)}, passedAccPlusOne);
// children.reduce(reduceFunction, initialValue); reduceFunction в нашем случае - обертка вокруг самописного reduce

Я кажется нашёл ответ, но нужно ваше подтверждение


Действия:
1 - В newAcc попадает единица
2 - При запуске children.reduce, значения с переменной newAcc переходит в параметр iAcc встроенной функции reduce
Всё верно?

Да, все правильно