I’m experimenting with JavaScript, and just for learning purposes, I was writing a forEach iterator that can iterate through nested arrays or any other iterable object that include a length property.
This is what I wrote:
var forEach = function(obj, callback, options) {
var options = options || {};
var context = options.context || this;
if(!isEmpty(obj)) { // isEmpty function just evaluates `return !(!!obj.length);`
for(var x = 0; x < obj.length; x++) {
if(!isEmpty(obj[x]) && options.deep === true) {
forEach.call(context, obj[x], callback, options);
continue;
}
callback.call(context, obj[x]);
}
}
};
If I pass a nested array I get RangeError: Maximum call stack size exceeded:
forEach(['a', 'b', ['c', 'd']], function(x) {
console.log(x);
}, { deep: true });
But that only seems to happen if I check for length property in obj[x]
If I replace:
if(!isEmpty(obj[x]) && options.deep === true) {
For:
if((obj[x] instanceof Array) && options.deep === true) {
I will magically work. Hovewer, not only Arrays have a length property. String have it to, so It’s not a wide approach.
How can I prevent the RangeError but still check for length property?
EDIT: I’m running the example on NodeJS v0.8.12
Consider that
'a'[0][0][0][0][0][0][0]...is valid ad infinitum, and every value is typestring. If the type isstring, then you should not recursively iterate it. Note also thatfunctionobjects have alengthproperty, and afunctionargument could be a self-reference to thefunctionitself. This would cause another infinite recursion. I think it would probably make more sense to handle different types differently instead of trying to develop a catch-all function.You could also have a
maxLevelproperty that limits the depth of the recursion, with a default value of, say,10. This way infinite recursion should not be easily possible.Demo: http://jsfiddle.net/bjpx5/