Visit Mozilla.org

Référence de JavaScript 1.5 Core:Opérateurs:Opérateurs spéciaux:L'opérateur this

Un article de MDC.


Sommaire

[modifier] Résumé

Le mot-clé this fait référence à l'objet de contexte (ou objet courant). En général, dans une méthode, this fait référence à l'objet appelant.

Opérateur
Implémentation : JavaScript 1.0
Version ECMA : ECMA-262

[modifier] Syntaxe

this[.propriété]

[modifier] Description

this est en lecture seule.

L'objet de contexte peut être considéré comme un « paramètre caché » passé à la fonction. Quatre manières de passer this existent :

Type Déclenché par this
appel de méthode objet.méthode(arg1, arg2) objet
La méthode call de Function fonction.call(objet, arg1, arg2) objet
La méthode apply de Function fonction.apply(objet, [arg1, arg2]) objet
Gestion d'un évènement DOM un évènement la cible de l'évènement dont le gestionnaire est une propriété

Le dernier cas (gestion d'un évènement) n'est en réalité pas intrinsèque à JavaScript. Les évènements font partie du DOM, pas de JavaScript, c'est-à-dire que le moteur JavaScript n'a rien à voir avec les évènements. (JavaScript fournit simplement une liaison vers le DOM.)

Si aucune de ces manières n'est utilisée, c'est l'objet global qui est passé comme objet de contexte.

[modifier] Liaison de méthodes

Du fait du « passage » de this aux fonctions, this n'a pas de valeur fixe pour une fonction. Cela signifie qu'une fonction n'a pas de « propriétaire » ou de « parent », même s'il s'agit d'une méthode. En d'autres mots, une méthode n'est pas liée à l'objet dont elle est une méthode.

Pour illustrer le concept de liaison, examinons le code suivant :

function Voiture(marque) {
   this.marque = marque;
}
Voiture.prototype.getMarque = function() {
   return this.marque;
}
var foo = new Voiture('toyota');
alert(foo.getMarque());

Comme on peut s'y attendre, ceci affiche « toyota ».

var marque = 'pas une voiture';
var bar = foo.getMarque;
bar();

De manière inattendue, ceci affichera « pas une voiture » plutôt que « toyota ». Comme bar() n'est pas un appel de méthode, l'objet de contexte n'est pas passé. La valeur de this est alors par défaut l'objet global, qui est window dans l'environnement d'un navigateur. L'objet global, lui aussi, a une propriété appelée marque dont la valeur est "pas une voiture". S'il n'avait pas de propriété appelée marque, on aurait plutôt vu s'afficher "undefined".

Ceci indique que bar n'est en aucune manière lié à foo. Ou plutôt, que la fonction à laquelle font référence bar et foo.getMarque n'est pas liée à son « objet parent », foo. Un objet peut disposer d'une propriété faisant référence à la fonction, mais celle-ci n'appartient pas à l'objet. La distinction entre méthodes et fonctions se fait uniquement au moment de l'appel : les appels de méthode passent l'« objet parent » comme valeur de this, tandis que les appels de fonctions passent l'objet global en tant que this.

Spécifiquement, la valeur de this au sein de la fonction n'est pas automatiquement fournie par foo. Au lieu de cela, this provient de l'appel de fonction. C'est-à-dire que dans l'expression foo.getMarque(), foo est passé en tant que this à la fonction à laquelle fait référence foo.getMarque. Chacune des lignes suivantes est équivalente :

foo.getMarque();
bar.call(foo);
foo.getMarque.call(foo);

Cette absence de lien avec les méthodes est volontaire. Elle permet aux méthodes d'être « partagées » ou « déplacées » d'un objet à l'autre. Pour faire suite à l'exemple suivant :

function Avion(marque) {
   this.marque = marque;
}
var avion = new Avion('airbus');

avion n'a pas de méthode getMarque, mais il dispose d'une propriété marque, ce qui le rend compatible avec la méthode code>getMarque</code> de Voiture. Par conséquent, la fonction à laquelle Voiture.prototype.getMarque fait référence peut être « partagée » avec un objet construit avec Avion ou avec Avion.prototype (ce qui ajouterait la méthode à tous les objets construits avec Avion ):

Avion.prototype.getMarque = Voiture.prototype.getMarque;
alert(avion.getMarque());

La fonction n'est pas réellement copiée. Elle est partagée ; Avion.prototype.getMarque et Voiture.prototype.getMarque font référence au même objet Function. Par exemple :

Avion.prototype.getMarque.nouvelle_propriété = 'hello';
alert(Voiture.prototype.getMarque.nouvelle_propriété);

Ce code affichera « hello », ce qui indique qu'Avion.prototype.getMarque et Voiture.prototype.getMarque ne font qu'un.

Il est facile de rencontrer ce problème lors du passage d'une méthode d'objet comme fonction de callback. Par exemple en utilisant setTimeout() ou addEventListener() :

setTimeout(objet.fonction, 1000); // passe la mauvaise valeur pour |this| !
document.addEventListener("load", objet.fonction, false); //  passe la mauvaise valeur pour |this| !

Une manière simple de contourner cela est de passer une fonction anonyme comme callback

document.addEventListener("load", function(event) { objet.fonction(event); }, false);

Notez qu'en faisant cela, une fermeture sera créée pour garder tous les objets vers lesquels pointent les variables locales dans la même visibilité, il conviendra donc de faire attention à ne pas provoquer de fuites de mémoire.

Une autre option dans le cas d'addEventListener() est de passer un objet avec une méthode handleEvent() :

var objet = {
  // ...
  handleEvent: function(e) {
    // ...
  }
}
document.addEventListener("load", objet, false)

[modifier] Exemples

[modifier] Exemple : utilisation de this dans un gestionnaire d'évènement

Supposons qu'une fonction appelée validation serve à valider la propriété valeur d'un objet, à partir de l'objet et de bornes inférieure et supérieure pour cette valeur :

function validation(objet, min, max) {
   if ((objet.valeur < min) || (objet.valeur > max))
      alert("Valeur non valide.");
}

On pourrait appeler validation dans chaque gestionnaire d'évènement onChange des contrôles d'un formulaire, en utilisant this pour passer l'élément de formulaire, comme dans l'exemple suivant :

<b>Entrez un nombre entre 18 et 99 :</b>
<input type="text" name="age" size="3"
   onchange="validation(this, 18, 99);"/>