This exhibits a classic recursion antipattern: passing the result (sum
) down the call stack as a parameter while also trying to pass it up as a result, leading to a confused state of affairs and double-counting.
Here's a fundamental rule of thumb for recursion: data dependencies (the things used to compute a result) are the parameters, results are return values.
Make sum
local to the frame, then accumulate on it during the frame, either because each element is a number (leaf node in the tree search) or it's a child that should be explored recursively. Don't return
immediately in the loop or you will miss some of the children.
function nestedEvenSum(obj) {
let sum = 0;
for (const k in obj) {
if (obj[k].constructor === Object) {
sum += nestedEvenSum(obj[k]);
}
else if (typeof obj[k] === "number" && obj[k] % 2 === 0) {
sum += obj[k];
}
}
return sum;
}
const obj = {
a: 2,
c: {
c: {
c: 2
},
cc: 'b',
ccc: 5
},
e: {
e: {
e: 2
},
ee: 'car'
}
};
console.log(nestedEvenSum(obj));
Note that this algorithm ignores arrays.
Also note that the function's design is highly rigid due to the % 2 === 0
predicate. You might consider using a function that traverses any nested structure and returns an array or generator of results that can then be filtered, or a function that allows an arbitrary callback predicate to perform the filtering.
One exception to the one-way data flow rule is that sometimes you'll want to accumulate results onto a parameter array as an optimization rather than returning and merging multiple arrays as you move back up the call stack, but that doesn't apply here.