Nouvelles Chroniques d'Amethyste

Penser au Sens, pas au Verbe

JavaScript: le mot clef this

Poster un commentaire

Le mot clef this peut sembler banal, mais en JavaScript il fonctionne différemment de C#.

Donc une petite étude sans prétention sur ce mot clef.

Les spécifications EcmaScript disent ceci:

The this keyword evaluates to the value of the ThisBinding of the current execution context.

ThisBinding est la valeur associée au contexte d’exécution.

En français, this ne représente pas l’instance de la classe en cours comme en C#, mais le propriétaire de la fonction. Comme souvent du code va clarifier les choses:

alert(this); // object window (scope global)

(function () { alert(this); // object window (scope global)
})();

var monObj = {
toto : function () {alert(this);}
}

monObj.toto(); // object Object

On déclenche 3 alert().

Dans le premier cas, c’est clair, on est dans le scope global, c’est à dire window, d’où le résultat.

Dans le deuxième cas, window est propriétaire de la fonction (on aurait pu aussi écrire une expression de fonction et l’appeler). D’où le résultat également.

Dans le troisième cas, toto() est déclaré dans monObj. C’est donc monObj qui sera le propriétaire de la fonction. D’où la encore le résultat.

On retrouve incidemment le fait qu’en JavaScript, l’unité de scope est la fonction, pas un bloc.

Il est parfois intéressant de modifier par code le propriétaire, c’est à dire la valeur de this.

var valeur=20; // dans le scope global

var monObj = {
valeur: 10, // dans l’objet
 toto : function () {alert(this.valeur);}
};

monObj.toto(); // this est l’objet (affiche 10)

(monObj.toto.bind(this))(); // this est le scope global (affiche 20)

monObj.toto(); // this est à nouveau l’objet affiche (10)

Cet exemple montre comment le même code retourne un résultat très différent selon la valeur de this.

On peut modifier le contexte sans la méthode bind().

var data = {name: »Alexis », age:14};

var user = {
data    :{name: »T. Woods », age:37},
showData:function () {  alert (this.data.name +  »  » + this.data.age);   }
}

user.showData(); // T.Wood

var showUserData = user.showData;
showUserData (); // Samantha 12

Lors du premier appel, this contient user, on affiche donc user.data, soit T.Wood.

On créé une variable showUserData dans le scope global à laquelle on affecte user.showData. Le contexte this change de valeur et devient window. On affiche alors window.data.

Un cas très important qui illustre cette notion est la déclaration des événements en JavaScript. Mais cela fera l’objet d’un article spécifique.

Retenez donc ceci: une valeur est assignée à this, uniquement au moment où la fonction qui le contient est appelée.

Fonction anonyme

Et si la fonction est une fonction anonyme comme sur cet exemple trouvé ici:

var user = {
town: »Paris »,
data      :[ {name: »T. Woods »},
{name: »P. Mickelson »} ],

clickHandler:function () {
this.data.forEach (function (person) {
alert (« Qui suis-je?  » + this); //[object Window]
alert (person.name +  » habite à  » + this.town); })
}
}

user.clickHandler();

On définit un objet user avec une propriété ville et data, un tableau d’objets contenant une unique propriété name. User contient aussi la méthode clickHandler.

Analysons un peu les choses.
ClickHandler invoque la méthode this.data.forEach(). Puisque user est le propriétaire de clickHandler, alors this se réfère à user.data. On va donc parcourir les deux noms de ce tableau.
La boucle contient deux alert, on s’attend donc à recevoir 4 popups.

Les deux alert sont exprimés dans une fonction anonyme. Que contient alors this?

Nous le découvrons avec le premier alert(). This contient window. Cela signifie que le propriétaire d’une fonction anonyme ne sera pas user, mais le scope global.

C’est donc la raison pour laquelle this.town contient invariablement undefined car town n’est pas définit dans le scope global.

Par contre person.name contient bien un des deux noms de user.data.

Comment faire pour afficher le nom de la ville dans ces conditions? La méthode standard consiste à introduire une variable intermédiaire dans le scope de user.

clickHandler:function () {

var that= this;
this.data.forEach (function (person) {
alert (« Qui suis-je?  » + this); //[object Window]
alert (person.name +  » habite à  » + that.town); })
}

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s