7
votes

Récursion ne fonctionne pas sans déclarer une variable globale

Pourquoi la version est-elle une solution mais la version B ne le fait pas? Comment faire fonctionner la version B sans déclarer une variable globale en dehors de la fonction (qui est une mauvaise pratique)? Je ne sais pas pourquoi je ne peux pas simplement déclarer compter à l'intérieur de la fonction elle-même.

a) xxx

b) xxx < / pré>


2 commentaires

Pour ce que ça vaut la peine, votre problème n'a rien à voir avec "Pass par référence", ce qui n'est pas possible dans JavaScript de toute façon.


Y a-t-il une raison pour laquelle vous ne faites pas élément.queryselectorall ('div'). Longueur> 5 ?


5 Réponses :


2
votes

La version B ne fonctionnera pas car chaque fois que la fonction est appelée compteur est redéclamé, donc compteur ne pas incréments.


2 commentaires

Merci, ça a du sens! Une suggestion était de faire compter un paramètre. Si je fais cela, comment puis-je le gérer à l'intérieur de la fonction?


Voir @fullstacks Réponse ci-dessous sur la déclaration de valeur par défaut pour le paramètre de comptage. Ce serait la meilleure solution si vous souhaitez éviter de déclarer une variable externe.



7
votes

Ce que vous avez vraiment besoin est deux fonctions em>, une à l'intérieur de l'autre: xxx pré>

dans cette configuration, vous passez dans une référence d'élément, puis la fonction extérieure appelle la fonction interne après l'initialisation du compteur. p>


Original pas très bonne réponse ici em> p>

Votre deuxième version ("BE" "En tant que variable locale forte> de la fonction. Chaque invocation de la fonction obtient sa propre variable "comptage" et dans chaque invocation, la première chose qui se produit est qu'elle est initialisée à zéro. P>

Si vous ne voulez pas de global, vous pouvez utiliser un Fermeture: P>

 var containsFiveOrMoreDivs = function() {
    var count = 0;
    return function(domElement) {
      if (domElement && domElement.tagName === "DIV") {
        count++;
      }

      //base case: 

      if (count >= 5) {
        return true;
      } else {
        if (domElement.hasChildNodes()) {
          var children = domElement.childNodes;
          for (var i = 0; i < children.length; i++) {

            if (containsFiveOrMoreDivs(children[i])) {
              return true;
            }

          }
        }
        return false;
      }
    };
  }();


0 commentaires

2
votes

Votre fonction récursive doit consommer le compte comme argument. La façon dont vous l'avez initialement initialisera compter à 0, quel que soit le nombre de fois que vous recursez.

Voici un exemple de fonction récursive qui consomme "le nombre de fois à faire quelque chose" comme paramètre. Modifiez-le pour soutenir votre cas. Votre cas de base serait quelque chose comme «Compte est supérieur à 5» et chaque fois que vous appelez de manière récursive, vous ajoutez 1 au compte que vous fournissez à l'appel récursif. P>

function executeMany(fn, count) {
    if (count > 0) {
        fn();
        executeMany(fn, count - 1)
    }
}

// this logs "Test" to the console twice
executeMany(function() { console.log("Test"); }, 2);


1 commentaires

Merci! Si je déclare compter comme un paramètre, comment le gérer à l'intérieur du corps de la fonction?



3
votes

variables en JavaScript existe dans la portée de la fonction. Chaque fois que vous appelez contendefiveormoreivs, le nombre sera toujours de 0 dans votre version B. Par conséquent, une récursion infinie.

Ce que vous pouvez faire, cependant, est de passer à chaque fois que vous appelez à l'intérieur de la fonction et utilisez-le ( S'assurer qu'il est initialisé correctement la première fois): xxx

appelez simplement que vous êtes actuellement ( contenantfiveormoreivs ('ElementName');


2 commentaires

Cela ne fonctionne pas, il suffit de le tester dans la console à propos de: vide après Ajout de 5 divs! il retourne faux.


Bon point - cela fonctionnera si les DIV sont imbriquées sous l'autre, mais cela ne comptera pas les frères et sœurs! Ce problème s'applique également à la solution de @fullstack ci-dessous. @Pointy - Votre solution semble assez élégante, mais chaque fois que vous appelez contenantfiveormoreivs (enfants [i]) dans la fonction renvoyée, vous retournez A neuf Fermeture qui a une variable de comptage frais de la valeur 0.



2
votes

Vous pouvez définir la fonction avec un paramètre code> code> et transmettre une valeur initiale ou si vous utilisez un CELMA 16, vous pouvez définir une valeur par défaut pour le paramètre en faisant compte = 0 .

var containsFiveOrMoreDivs = function(domElement, count) {
    if (domElement && domElement.tagName === "DIV") {
      count++;
    }


    //base case: 

    if (count >= 5) {
      return true;
    } else {
      if (domElement.hasChildNodes()) {
        var children = domElement.childNodes;
        for (var i = 0; i < children.length; i++) {

          if (containsFiveOrMoreDivs(children[i]), count) {
            return true;
          }

        }
      }
      return false;
    }
  };

// call function and set counter to some initial value, such as zero
containsFiveOrMoreDivs(domElement, 0);


2 commentaires

C'était exactement ce que j'allais dire @freezycold. Grande solution.


C'est génial et cela fonctionnera dans Firefox et aucun autre navigateur actuel.