# JavaScript: Calling back from inside callbacks & recursion

Let’s say you have an array of arrays:

``````var a = [1, 2, 3];
var b = [4, 5, 6];
var c = [7, 8, 9];
var abc = [a, b, c];
``````

You can define a callback:

``````var lessThan5 = function (val) { return val < 5; };
``````

and then call it on any of the single-letter arrays:

``````a.every(lessThan5);  // true
c.every(lessThan5);  // false
``````

But what if what you really want to do is test whether every atomic value in the three subarrays held by abc is less than 5? You could (incorrectly) try this:

``````abc.every(lessThan5);  // false, but not testing what you believe
``````

To see that it’s not working as we want it to, let’s create this callback:

``````var greaterThan0 = function (val) { return val > 0; };
``````

Since every value in every array held by abc is > 0, we want this callback to return true, but it still returns false:

``````abc.every(greaterThan0);  // false
``````

abc.every is looping over an array of arrays, not an array of primitives (integers). What we really want is to have the callback called once for each array in abc call array.every(greaterThan0) on whatever array it receives. We need an intermediate callback, or a callback that calls .every() with another callback. How might we do this?

``````abc.every(function (array) { return array.every(greaterThan0); });  // true!
``````

This works. We can prove this by adding a fourth array holding a negative value and watching the function return false:

``````d = [-1, 10, 11];
abc.push(d);
abc.every(function (array) { return array.every(greaterThan0); });  // false
``````

But this is messy and gets even messier if you add another layer (or more) of callbacks. How can we clean this up?

Instead of using a function literal as our first callback, we can store the function in a named variable and pass in the variable:

``````var arrayGreaterThan0 = function (array) { return array.every(greaterThan0); };
abc.every(arrayGreaterThan0);
``````

To summarize:

``````var greaterThan0 = function (val) { return val > 0; };   // inner callback
var arrayGreaterThan0 = function (array) {               // outer callback
return array.every(greaterThan0);
};
abc.every(arrayGreaterThan0);                            // invocation on abc
``````

What if we don’t know till runtime how many levels down into subarrays we must descend before we hit primitive values? Then the callback can’t know in advance whether it’s being handed an array of arrays or an array of primitives. But it can test what it has been handed and either call itself (if it has received an array of arrays) or call greaterThan0 (if handed an array of primitives):

``````var greaterThan0 = function (val) { return val > 0; };   // leaf-level callback
var arrayGreaterThan0 = function (array) {               // recursive outer callback
if (Array.isArray(array)) {
return array.every(arrayGreaterThan0);
} else {
return array.every(greaterThan0);
}
};
abc.every(arrayGreaterThan0);  // false
``````

If arrays are wrapped inside arrays inside other arrays, it will recursively descend down and down, however far it needs to, till it hits primitive values.

To make sure this works correctly for our array of arrays, let’s change a value and confirm the result changes:

``````abc === -1;  // true
abc = 43;
abc.every(arrayGreaterThan0);  // true
``````

Now let’s test the recursion against an array of arrays of arrays:

``````var aaa = [[[1,2],[3,4]],[[5,6],[7,8]]];
aaa.every(arrayGreaterThan0);  // true

aaa = -10;
aaa.every(arrayGreaterThan0);  // false
``````

But what if the original array is simply an array of integers? It fails!

``````simple_array = [1, 2, 3];
simple_array.every(arrayGreaterThan0);  // "TypeError: Object 1 has no method 'every'"
``````

We’ve assumed the original array is at least an array of arrays. If it’s a simple array, the callback fails. How can we correct this? Instead of assuming we received an array and testing what its child is, we can test what we’re actually handed and respond accordingly:

``````var greaterThan0 = function (val) { return val > 0; };   // leaf-level callback
var objGreaterThan0 = function objGreaterThan0(obj) {    // recursive outer callback
if (Array.isArray(obj)) {                              //   not yet at leaf level
return obj.every(objGreaterThan0);                   //     recurse
} else {                                               //   at leaf level
return greaterThan0(obj);                            //     call leaf-level callback
}
};

simple_array = [1, 2, 3];
simple_array.every(objGreaterThan0);    // true

simple_array.push(-66);
simple_array.every(objGreaterThan0);    // false
``````

And it still works with arrays inside arrays inside arrays:

``````var aaa = [[[1,2],[3,4]],[[5,6],[7,8]]];
aaa.every(objGreaterThan0);             // true

aaa = -10;
aaa.every(objGreaterThan0);             // false
``````

This is probably not the cleanest, most efficient solution, but it works. More to come.

Posted by James on Friday, March 22, 2013