I really like the site Codewars. They don’t give you a breakdown on how to solve the problems, but what ends up happening is you keep plugging away until you get the correct answer, and then you get to see how everyone else did it. Chances are you’ll see a solution that was similar to what you did, but maybe just a bit closer to what you were aiming for. So then you try the same problem again, but with that new approach. It’s great practice.
As for callbacks and the reduce method in particular, yep it can be a lot to get your head around. With your first example, the imperative approach, at least you can point your finger at the code and say “okay I’m at this spot and this is what is happening, and next I go to…” and then you move your finger to the next thing that happens. You can’t do that as easily or sometimes at all with the declarative approach. For example, the filter method for finding items that are greater than 2:
array.filter(item => item > 2);
There’s no following along there! Just a bunch of magic behind the scenes. You’ve given a callback but who knows how it’s being used. But, over time, the declarative approach can actually become easier to read than the imperative approach. You can more quickly see what the code is doing despite not knowing exactly how it is done.
As for understanding the conversion from an imperative approach to array.reduce, that’s a good question, and I don’t know that I have a good answer. However, I think there’s a bit too much going on in the countOccurrences exercise. I’d start even simpler, like a function that gets the sum of the numbers in an array. First you’d try the imperative approach:
function sum(array) {
let total = 0;
for (let item of array) {
total = total + item;
}
return total;
}
Then you could try replacing the names of the variables with the names that you would see in the reduce function:
function sum(array) {
let accumulator = 0;
for (let current of array) {
accumulator = accumulator + current;
}
return accumulator;
}
And then you’d try the reduce version:
function sum(array) {
return array.reduce((accumulator, current) => {
return accumulator + current;
}, 0);
}
And maybe that middle step can help connect the concepts from the two approaches.