Précédent   Forum des professionnels en informatique > Webmasters - Développement Web > Contribuez
Contribuez Proposez vos articles, cours, tutoriels, questions/réponses pour les FAQ, sources et autres ressources pour la rubrique Web ainsi que ses sous-rubriques.
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 04/01/2012, 04h49   #1
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 872
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 872
Points : 1 381
Points : 1 381
Par défaut Function Récursive

Bonjour à tous,

je viens d'utiliser une fois encore la fameuse ligne de récursion d'une fonction :


Code :
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
quand soudain je me suis rendu compte, qu'il était possible de mettre tout ça sous forme d'une fonction :

Code :
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
les plus attentifs d'entre vous auront remarqué que hélas, ça ne FONCTIONNE PAS (sur aucun des 3 navigateurs les plus populaires) !

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":

Code :
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
ne me demandez pas d'explications, ça me dépasse totalement, mais soit continuons...

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 :

Code :
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
qui fonctionne donc bien sous les 3 navigateurs.

Et finalement pour ceux qui souhaiteraient conserver et utiliser l'objet "this" dans leurs appels récursifs :

Code :
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)
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).


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 :
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
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 05/01/2012, 00h09   #2
Rédacteur
 
Avatar de danielhagnoul
 
Homme Daniel Hagnoul
Étudiant perpétuel
Inscription : février 2009
Messages : 3 221
Détails du profil
Informations personnelles :
Nom : Homme Daniel Hagnoul
Âge : 61
Localisation : Belgique

Informations professionnelles :
Activité : Étudiant perpétuel
Secteur : Enseignement

Informations forums :
Inscription : février 2009
Messages : 3 221
Points : 6 767
Points : 6 767
Bonsoir

'caller', 'callee', et 'arguments' c'est obsolète.

Citation:
Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them.
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<script>
	"use strict";
 
	var operation = function(n1, n2, op){
			// debug
			//console.log( n1, n2, op, parseFloat( eval(n1 + op + n2) , 10 ) );
 
			return parseFloat( eval(n1 + op + n2) , 10 );
		},
		multiOperation = function(tab, op){
			var r = 0;
 
			for(var i in tab){
				if (i != 0){
					r = operation(r, tab[i], op);
				} else {
					r = tab[i];
				}
			}
 
			return r;
		};
 
	console.log( "multiOperation( [2, 3, 4, 5], '+' ) = ", multiOperation( [2,3,4,5], '+' ) );
	console.log( "multiOperation( [2, 3, 4, 5], '*' ) = ", multiOperation( [2,3,4,5], '*' ) );
	console.log( "multiOperation( [2, 3, 4, 5], '-' ) = ", multiOperation( [2,3,4,5], '-' ) );
	console.log( "multiOperation( [2, 3, 4, 5], '/' ) = ", multiOperation( [2,3,4,5], '/' ) );
</script>
__________________

FAQ jQuery

Mon cahier d’exercices sur jQuery & Co

Si un message vous a aidé ou vous semble pertinent, votez pour lui !
danielhagnoul est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 05/01/2012, 17h55   #3
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 872
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 872
Points : 1 381
Points : 1 381
oui, une simple boucle fait aussi l'affaire, mais en général, j'ai tendance à souvent utiliser la récursion pour la facilité de codage.

mais la ligne en javascript est vraiment longue donc je l'ai simplement rendu appelable via une fonction.

le dernier usage que j'en ai fait :

Code :
1
2
3
function restesChinois(e1,e2){ // (x == e1[0] mod e1[1]) && (x == e2[0] mod e2[1])
	return recurse(arguments),[(invMod(e2[1],e1[1])*e2[1]*e1[0]+invMod(e1[1],e2[1])*e1[1]*e2[0])%(e1[1]*e2[1]),e1[1]*e2[1]];
}
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 06h25.


 
 
 
 
Partenaires

Hébergement Web