Bonjour à tous,
je viens d'utiliser une fois encore la fameuse ligne de récursion d'une fonction :
quand soudain je me suis rendu compte, qu'il était possible de mettre tout ça sous forme d'une fonction :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 function somme(n1,n2){ // appels récursives si le nbr d'arguments > 2 if(arguments.length>2) arguments[1] = arguments.callee.apply(this,[].slice.call(arguments,1)); // renvoie la somme des 2 premiers arguments return n1+n2; } // exemple d'appel alert(somme(2,3,4,5)); //14
les plus attentifs d'entre vous auront remarqué que hélas, ça ne FONCTIONNE PAS (sur aucun des 3 navigateurs les plus populaires) !
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 function recurse(a,c){ a = (c = arguments.callee.caller).arguments; if(a.length>2) a[1] = c.apply(this,[].slice.call(a,1)); } function somme(n1,n2){ recurse(); return n1+n2; } // exemple d'appel alert(somme(2,3,4,5)); // 5
nous arrivons maintenant à mon passage préféré, l'ajout du code très très utile arguments; corrige miraculeusement le bug (sur les 3 navigateurs) placé indifférement avant, après ou pendant(arguments=recurse(); ou recurse(arguments);) l'appel de "recurse":
ne me demandez pas d'explications, ça me dépasse totalement, mais soit continuons...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 function recurse(a,c){ a = (c = arguments.callee.caller).arguments; if(a.length>2) a[1] = c.apply(this,[].slice.call(a,1)); } function somme(n1,n2){ /*arguments;*/ /*arguments=*/recurse(/*arguments*/); /*arguments;*/ // en décommentant n'importe lequel de ces "arguments" ci-dessus, // le code retournera la bon résultat : 14 return n1+n2; } // exemple d'appel alert(somme(2,3,4,5)); // 14
je trouve cette solution effroyablement moche, il est donc de bon ton de trouver un compromis qui garderai notre appel "simple" mais fonctionnel, voici donc la solution finale que je vous propose, en utilisant le mot "arguments" comme paramètre :
qui fonctionne donc bien sous les 3 navigateurs.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 function recurse(a){ if(a.length>2) a[1] = arguments.callee.caller.apply(this,[].slice.call(a,1)); } function somme(n1,n2){ recurse(arguments); return n1+n2; } // exemple d'appel alert(somme(2,3,4,5)); // 14
Et finalement pour ceux qui souhaiteraient conserver et utiliser l'objet "this" dans leurs appels récursifs :
Voila, en espérant que certains se servent de ma fonction "recurse" et que d'autres commentent l'étrange comportement des "arguments" (que je reconnais maltraiter comme pas possible avec des caller d'appels récursifs).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 function recurse(a){ if(a.length>2) a[1] = arguments.callee.caller.apply(this,[].slice.call(a,1)); } function somme(n1,n2){ // appels récursives si le nbr d'arguments > 2 avec conservation de l'objet courant recurse.call(this,arguments); // sauvegarde des sommes intermédiaires dans l'objet courant this.log.push(n2); // renvoie la somme des 2 premiers arguments return n1+n2; } // exemple d'appel var o = {log:[],somme:somme}; alert(o.somme(2,3,4,5)); // 14 alert(o.log); // [5,9,12] => (5,5+4,5+4+3)
Willpower.
edit:je vous ai proposé la version "basique" qui considère qu'on a 2 arguments par appel, mais on pourrait concevoir un découpage de récursion sur plus de 2 arguments où le nombre de paramètre serait passé en argument à la fonction recurse. aussi, l'ordre des appels récursif se fait de droite à gauche et l'opération doit être commutatif pour un bon résultat attendu.
----------------------------
en résumé :
(testé sous : IE, firefox, chrome, safari & opera)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 var r = function(a){if(a.length>2)a[1]=arguments.callee.caller.apply(this,[].slice.call(a,1))}; function somme(n1,n2){ r(arguments); return n1+n2; } function produit(n1,n2){ r(arguments); return n1*n2; } alert(somme(2,3,4,5)); // 14 alert(produit(2,3,4,5)); // 120
Partager