2013-01-22 2 views
1

J'expérimente JavaScript, et juste pour apprendre, j'écrivais un itérateur forEach qui peut itérer à travers les tableaux imbriqués ou tout autre objet itératif qui comprend un length property.Erreur maximale de la taille de la pile d'appels sur l'itérateur récursif

C'est ce que je l'ai écrit:

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]); 
    } 
    } 
}; 

Si je passe un tableau imbriqué je reçois RangeError: Maximum call stack size exceeded:

forEach(['a', 'b', ['c', 'd']], function(x) { 
    console.log(x); 
}, { deep: true }); 

Mais cela ne semble se produire si je vérifie la propriété de longueur dans obj[x]

Si je remplace:

if(!isEmpty(obj[x]) && options.deep === true) { 

Pour:

if((obj[x] instanceof Array) && options.deep === true) { 

je vais travailler par magie. Hovewer, non seulement Arrays ont une propriété de longueur. String l'a, donc ce n'est pas une approche large. Comment puis-je empêcher le RangeError mais toujours vérifier length property?

EDIT: Je exécuter l'exemple sur NodeJS v0.8.12

+0

Considèrent que ' 'a' [0] [0] [0] [0] [0] [0] [0] ...' est ad infinitum valide et chaque valeur est de type 'string'. Si le type est 'string', vous ne devriez pas l'itérer récursivement. – mellamokb

+0

@mellamokb Oui, je suppose que cela a plus de sens :) – jviotti

+0

@mellamokb S'il vous plaît poster votre suggestion comme une réponse afin que je puisse l'accepter – jviotti

Répondre

0

Tenir compte que 'a'[0][0][0][0][0][0][0]... est ad infinitum valide, et chaque valeur est de type string. Si le type est string, vous ne devez pas l'itérer récursivement. Notez également que les objets function ont une propriété length et qu'un argument function peut être une référence automatique au function lui-même. Cela provoquerait une autre récursion infinie. Je pense qu'il serait probablement plus logique de gérer différents types différemment au lieu d'essayer de développer une fonction fourre-tout. Vous pouvez également avoir une propriété maxLevel qui limite la profondeur de la récursion, avec une valeur par défaut de 10, De cette façon, la récursion infinie ne devrait pas être facilement possible.

forEach(['a', 'b', ['c', 'd']], function(x) { 
    console.log(x); 
}, { deep: true, maxLevel: 10 }); 

var forEach = function(obj, callback, options, level) { 
    var options = options || {}; 
    var context = options.context || this; 

    if (!level) level = 1; 
    if (!options.maxLevel) options.maxLevel = 10; 

    if (level > options.maxLevel) return; 
    ... 
     forEach.call(context, obj[x], callback, options, level + 1); 
    ... 
} 

Démo: http://jsfiddle.net/bjpx5/

Questions connexes