Précédent   Forum des professionnels en informatique > Webmasters - Développement Web > JavaScript
JavaScript Forum programmation JavaScript. Lire : Cours JavaScript, FAQ JavaScript, Toutes les FAQ JavaScript et Sources JavaScript
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 24/08/2011, 07h53   #1
Invité de passage
 
Homme
Inscription : mars 2011
Messages : 2
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Hérault (Languedoc Roussillon)

Informations forums :
Inscription : mars 2011
Messages : 2
Points : 0
Points : 0
Par défaut This faisant référence au mauvais objet

Bonjour,

J'ai récemment décidé de me mettre à la "POO" avec Javascript. J'utilise donc le prototypage, mais j'ai un soucis au niveau du code suivant (version simplifiée de mon code) :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var maClasse = function(cadreCible){
	this.cadre = cadreCible;
	this.boite = this.add();
}
 
maClasse.prototype = {
	add : function(){
		// Divers opérations dont celle ci-dessous
		monBouton.addEventListener('click',this.remove,false);
	}
	remove : function(){
		this.cadre.removeChild(this.boite);
	}
}
Lorsque je créé une instance de cette classe, je passe en argument un cadre (div), que j'affecte à la propriété cadre. La méthode add est alors appelée, ajoute des éléments au DOM, et renvoie l'élément principal ajouté à la propriété boite.

Dans la méthode add, je fais appel à un addEventListener pour executer une fonction au clic sur un bouton.

Le soucis est le suivant : dans la méthode remove, this ne fait plus référence à ma classe mais à monBouton.

Sauriez vous comment je pourrais faire référence aux propriétés cadre et boite dans la méthode remove ?

Je vous remercie d'avance.
threonine est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/08/2011, 10h43   #2
Membre régulier
 
Inscription : octobre 2010
Messages : 65
Détails du profil
Informations forums :
Inscription : octobre 2010
Messages : 65
Points : 87
Points : 87
Salut !

En JavaScript utilisation du mot clef this dans une fonction, référence l’instance de l’objet qui maintien la référence sur cette fonction.

Je m’explique, le gestionnaire d’événement du bouton garde une référence sur ta fonction remove, c’est donc le bouton qui appelle la fonction remove, changeant ainsi le context d’appelle , this référence donc le bouton .

Il existe plusieurs méthodes pour sauvegarder le context d’appelle (this) , personnellement j’utilise le prototypage de fonction pour y ajouter une mécanique de delegate, comme ce ci :
Code :
1
2
3
4
5
Function.prototype.Delegate = function(obj)
{
    var method = this;
    return function() { return method.apply(obj, arguments); };
};
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var maClasse = function(cadreCible){
	this.cadre = cadreCible;
	this.boite = this.add();
}
 
maClasse.prototype = {
	add : function(){
		// Divers opérations dont celle ci-dessous
		monBouton.addEventListener('click',this.remove.Delegate(this),false);
	},
	remove : function(){
		this.cadre.removeChild(this.boite);
	}
}
p3ga5e est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/08/2011, 10h53   #3
Responsable Développement Web

 
Avatar de Bovino
 
Homme Didier Mouronval
Développeur Web
Inscription : juin 2008
Messages : 13 807
Détails du profil
Informations personnelles :
Nom : Homme Didier Mouronval
Âge : 41
Localisation : France, Gironde (Aquitaine)

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : juin 2008
Messages : 13 807
Points : 35 793
Points : 35 793
Une autre technique consiste à conserver la référence à this dans une variable :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var maClasse = function(cadreCible){
	var me = this;
	this.cadre = cadreCible;
	this.boite = this.add();
}
 
maClasse.prototype = {
	add : function(){
		// Divers opérations dont celle ci-dessous
		monBouton.addEventListener('click',me.remove,false);
	},
	remove : function(){
		this.cadre.removeChild(this.boite);
	}
}
Sans oublier de mettre une virgule entre les membres de l'objet prototype
__________________
Pas de question technique par MP !
Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
Vous possédez un blog et aimeriez diffuser vos billets sur le forum, contactez-moi !
Mes formations video2brain : La formation complète sur JavaScriptJavaScript et le DOM par la pratiquePHP 5 et MySQL : les fondamentaux
Mon livre sur jQuery
Bovino est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/08/2011, 15h35   #4
Membre éclairé
 
Homme
F5(){F5}
Inscription : avril 2008
Messages : 256
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : F5(){F5}
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : avril 2008
Messages : 256
Points : 320
Points : 320
La dernière ne marchera pas, me n'est pas dans le même scope. Par contre l'idée est la même :
Code :
1
2
3
4
function add(){
 var me = this;
 monBouton.addEventListener('click',me.remove,false);
}
galerien69 est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/08/2011, 19h10   #5
Expert Confirmé Sénior
 
Avatar de RomainVALERI
 
Homme Romain VALERI
POOête
Inscription : avril 2008
Messages : 2 573
Détails du profil
Informations personnelles :
Nom : Homme Romain VALERI
Âge : 35
Localisation : France, Meurthe et Moselle (Lorraine)

Informations professionnelles :
Activité : POOête

Informations forums :
Inscription : avril 2008
Messages : 2 573
Points : 4 075
Points : 4 075
Moi c'est plutot ce passage qui me chiffonne >>> this.boite = this.add(); .

Dans la mesure où la fonction add ne retourne aucune valeur... pourquoi vouloir stocker "rien" dans une propriété de l'objet ?
(si c'est parce que tu voulais à la fois créer cette propriété tout en laissant une valeur "undefined" ET que tu as voulu "gagner" une ligne, ne me l'avoue surtout pas ça va me faire du mal )
__________________

...pour les linguistes et les curieux >>> générateur de phrases aléatoires

__________________
RomainVALERI est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/08/2011, 20h29   #6
Membre régulier
 
Inscription : octobre 2010
Messages : 65
Détails du profil
Informations forums :
Inscription : octobre 2010
Messages : 65
Points : 87
Points : 87
Citation:
Envoyé par galerien69 Voir le message
La dernière ne marchera pas, me n'est pas dans le même scope. Par contre l'idée est la même :
Code :
1
2
3
4
function add(){
 var me = this;
 monBouton.addEventListener('click',me.remove,false);
}
Desolé mais cela ne resou pas le probleme initial !
le branchement de la méthode remove a l'evenement "Click" du bouton ne pose aucun problème ... mais c'est lors de l’exécution de la méthode remove que le problème survient !

tu doit confondre avec la technique de la fonction "anonyme" :
Code :
1
2
3
4
5
6
7
8
9
10
function add()
{
	var me = this;
	monBouton.addEventListener('click',
	function () // remove en fonction anonyme
	{
		me.cadre.removeChild(me.boite);
	},
	false);
}
pour moi cette technique ressemble plus a un Hack car on perd la mutualisation de la méthode remove!

l'autre technique viable, dont parlé Bovino, est de sauvegarder le context this dans une variable de la fonction contructeur
mais contrairement a son exemple il faut tous déclarer dans le contructeur,meme les methodes, et bannir l'utilisation du mot clef this
comme ceci :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
var maClasse = function(cadreCible)
{
	var me = this;
	// mot clef this est bannit a partir d'ici ...
	me.add = function()
	{
		// Divers opérations dont celle ci-dessous
		monBouton.addEventListener('click',me.remove,false);
	};
 
	me.remove = function()
	{
		me.cadre.removeChild(me.boite);
	};
 
	me.cadre = cadreCible;
	me.boite = me.add();
 
}
cette technique a l'avantage de garantir que me reference bien un type maClasse
mais ne support pas le prototypage
p3ga5e est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/08/2011, 22h02   #7
Membre éclairé
 
Homme
F5(){F5}
Inscription : avril 2008
Messages : 256
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : F5(){F5}
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : avril 2008
Messages : 256
Points : 320
Points : 320
Citation:
Desolé mais cela ne resou pas le probleme initial !
Comme tu las dit le probleme survient sur lexec du callback de onclick.

Lorsque add est appelée, on peut oser espérer que c'est sur maClasse.
Donc me=this pointe bien sur maClasse.

A fortiori lorsque me.remove est appelé, this réfère me, qui réfère bien maClasse.
galerien69 est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/08/2011, 02h57   #8
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 869
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 869
Points : 1 377
Points : 1 377
Vous êtes fous !

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var maClasse = function(cadreCible){
	this.cadre = cadreCible;
	this.boite = this.add();
};
 
maClasse.prototype = {
	add : function(){
		// Divers opérations dont celle ci-dessous
		var me = this;
		monBouton.addEventListener('click',function(){me.remove()},false);
	},
	remove : function(){
		this.cadre.removeChild(this.boite);
	}
};

ou plus largement

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function bind(fn,obj){
	return function(){return fn.apply(obj,arguments)};
}
//-----------------------------
var maClasse = function(cadreCible){
	this.cadre = cadreCible;
	this.boite = this.add();
};
 
maClasse.prototype = {
	add : function(){
		// Divers opérations dont celle ci-dessous
		monBouton.addEventListener('click',bind(this.remove,this),false);
	},
	remove : function(){
		this.cadre.removeChild(this.boite);
	}
};
edit: je n'avais pas vu la réponse de p3ga5e (dans le post #2) qui est tout aussi correcte. (sauf qu'il faut remplacer "call" par "apply").
Willpower est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/08/2011, 09h11   #9
Expert Confirmé Sénior
 
Avatar de RomainVALERI
 
Homme Romain VALERI
POOête
Inscription : avril 2008
Messages : 2 573
Détails du profil
Informations personnelles :
Nom : Homme Romain VALERI
Âge : 35
Localisation : France, Meurthe et Moselle (Lorraine)

Informations professionnelles :
Activité : POOête

Informations forums :
Inscription : avril 2008
Messages : 2 573
Points : 4 075
Points : 4 075
Citation:
Envoyé par Willpower Voir le message
Vous êtes fous !


@threonine : ça va ? y'a de quoi faire, là... tu t'en sors ? ^^
__________________

...pour les linguistes et les curieux >>> générateur de phrases aléatoires

__________________
RomainVALERI est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/08/2011, 10h25   #10
Membre régulier
 
Inscription : octobre 2010
Messages : 65
Détails du profil
Informations forums :
Inscription : octobre 2010
Messages : 65
Points : 87
Points : 87
Citation:
Envoyé par galerien69 Voir le message
Lorsque add est appelée, on peut oser espérer que c'est sur maClasse.
Donc me=this pointe bien sur maClasse.
Exacte mais le contraire n’est pas vrais ! Lors de l’exécution de la fonction remove this != me.
En EcmaScript this est redéfinit a chaque exécution, il peut pointer n’importe quel type …
soit le développeur détermine l’objet que this référencera grâce aux méthodes call et apply
sinon il référence l’objet qui maintient la référence sur la fonction … ce n’est pas très claire , un petit exemple pour illustrer mes propos :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
var f = function()
{
     alert(this.Name);
};
 
f(); // this devrait etre egale undefined , sur les navigateurs this = window
var refA = { Name : "A" , Display : f};
var refB = { Name : "B" , Display : f };
var refC = { Name : "C" , Display : f };
refA.Display(); // this = refA
refB.Display(); // this = refB
f.call(refC); // this = refC
Citation:
Envoyé par Willpower
edit: je n'avais pas vu la réponse de p3ga5e (dans le post #2) qui est tout aussi correcte. (sauf qu'il faut remplacer "call" par "apply").
Tu as parfaitement raison j’edit mon 1er post pour corrigé cela !

Citation:
Envoyé par RomainVALERI
@threonine : ça va ? y'a de quoi faire, là... tu t'en sors ? ^^
Je pense que l’on a réussi à le dégouter, définitivement, du Javascript
p3ga5e est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/08/2011, 10h40   #11
Membre habitué
 
Homme
Étudiant
Inscription : mai 2011
Messages : 226
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : mai 2011
Messages : 226
Points : 126
Points : 126
p3ga5e, pourquoi ça marche pas ça ? Po compris

Code :
1
2
3
4
function add(){
 var me = this;
 monBouton.addEventListener('click',me.remove,false);
}
edit : si, ça y est, je crois que j'ai compris : addEventListener va executer
Code :
this.cadre.removeChild(this.boite);
donc monBouton.addEventLIstener va executer
Code :
monBouton.cadre.removeChild(monBouton.boite);
c'est ça?
Sharcoux est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/08/2011, 10h59   #12
Membre régulier
 
Inscription : octobre 2010
Messages : 65
Détails du profil
Informations forums :
Inscription : octobre 2010
Messages : 65
Points : 87
Points : 87
Oui ! enfin presque !

La fonction remove n’est pas appelé lors du addEventListener, mais lors d’un click utilisateur, addEventListener ne fait que sauvegarder la référence de la fonction remove.

Mais le problème reste le même c’est bien monBouton qui appel la fonction remove donc this = monBouton lors de l'evenment click !
p3ga5e est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/08/2011, 12h09   #13
Membre éclairé
 
Homme
F5(){F5}
Inscription : avril 2008
Messages : 256
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : F5(){F5}
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : avril 2008
Messages : 256
Points : 320
Points : 320
Et boum!

toussa pour économiser un
Code :
function(){me.remove()}
, ca m'apprendra (dans les deux sens...)
galerien69 est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/08/2011, 12h38   #14
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 869
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 869
Points : 1 377
Points : 1 377
Citation:
Envoyé par Sharcoux Voir le message
p3ga5e, pourquoi ça marche pas ça ? Po compris

Code :
1
2
3
4
function add(){
 var me = this;
 monBouton.addEventListener('click',me.remove,false);
}
edit : si, ça y est, je crois que j'ai compris : addEventListener va executer
Code :
this.cadre.removeChild(this.boite);
donc monBouton.addEventLIstener va executer
Code :
monBouton.cadre.removeChild(monBouton.boite);
c'est ça?
Exacte ! (enfin comme dit p3ga5e, c'est pas addEvent qui va exécuter mais l’évènement lui-même)

alors qu'avec
Code :
function(){me.remove();/*this==monButton*/}
le this vaudra de nouveau "monBouton" mais peu importe puisqu'on ne l'utilisera pas et qu'on utilisera "me"(objet de maClasse) à la place. Et on appelera donc la méthode remove sur cette objet. et donc
Code :
this.cadre.removeChild(this.boite);
sera équivalent à
Code :
me.cadre.removeChild(me.boite);
avec me l'objet(de maClasse) qui a appelé "add" initialement.


edit:

Code :
monBouton.addEventListener('click',me.remove,false);
ne passe que la méthode "remove" comme argument, peu importe d'où tu la sors, le contexte ne joue que lors d'un appel(exécution).

c'est exactement comme si tu faisais :


Code :
monBouton.addEventListener('click',function(){this.cadre.removeChild(this.boite);},false);
puisque
Code :
me.remove == maClasse.prototype.remove == function(){this.cadre.removeChild(this.boite);}
Willpower est actuellement 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 16h50.


 
 
 
 
Partenaires

Hébergement Web