As you have discovered, placing the index parameter outside the function leads to the complication that it must be continually managed for the function to work. I would think that usually, assignments to write functions assume they will be self-contained rather than rely on global variables.
We can conceptualize reduce recursively like this:
function reduce(arr, fn, initial){
if (!arr.length)
return initial;
if (arr.length == 1)
return fn(initial, arr[0]);
return reduce(arr.slice(1), fn, fn(initial, arr[0]));
}
console.log(reduce([1,2,3], (a,b)=>a+b, 0)); // 6
In JavaScript, each call to slice produces a copy of that section of the array, making this version less efficient for larger inputs. One option to improve efficiency could be to have an inner recursive function that relies on two parameters, an index and an accumulator, that would traverse the array, but I'm not sure the verifier would allow it since the outer function would no longer be calling itself.
One more thing to watch out for in your code is that !initial would catch whenever initial is a value that evaluates to "falsy," not only when it is not passed in as a parameter.
Here's a "hack"ish (because it modifies fn, although we could modify it back :), index-based solution that does not require an extra parameter and uses the full 4 parameters of fn:
function reduce(arr, fn, initial){
if (fn.index === undefined)
fn.index = 0;
else
fn.index++;
if (fn.index == arr.length)
return initial;
return reduce(arr, fn, fn(initial, arr[fn.index], fn.index, arr));
}
console.log(reduce([1,2,3], (a,b)=>a+b, 0)); // 6
indexis stateful and will not be correct if you try to reduce more than one array.reducefunction, I prefer to just loop