mozilla

Revision 621771 of L'opérateur this

  • Revision slug: Web/JavaScript/Reference/Opérateurs/L_opérateur_this
  • Revision title: L'opérateur this
  • Revision id: 621771
  • Created:
  • Creator: teoli
  • Is current revision? Không
  • Comment

Revision Content

 

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

Syntaxe

this{{ mediawiki.external('. propriété ') }}

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, {{ mediawiki.external('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.

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)

Dans certain cas, on peut aussi utiliser "this" à travers une variable :

var obj = this;
document.addEventListener("load", obj.fonction, false);

 

Exemples

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);"/>

Revision Source

<p>&nbsp;</p>
<h3 id="R.C3.A9sum.C3.A9" name="R.C3.A9sum.C3.A9">Résumé</h3>
<p>Le mot-clé <code>this</code> fait référence à l'objet de contexte (ou objet courant). En général, dans une méthode, <code>this</code> fait référence à l'objet appelant.</p>
<table class="fullwidth-table">
 <tbody>
  <tr>
   <td class="header" colspan="2">Opérateur</td>
  </tr>
  <tr>
   <td>Implémentation&nbsp;:</td>
   <td>JavaScript 1.0</td>
  </tr>
  <tr>
   <td>Version ECMA&nbsp;:</td>
   <td>ECMA-262</td>
  </tr>
 </tbody>
</table>
<h3 id="Syntaxe" name="Syntaxe">Syntaxe</h3>
<p><code>this{{ mediawiki.external('.
 <i>
  propriété</i>
 ') }} </code></p>
<h3 id="Description" name="Description">Description</h3>
<p><code>this</code> est en lecture seule.</p>
<p>L'objet de contexte peut être considéré comme un «&nbsp;paramètre caché&nbsp;» passé à la fonction. Quatre manières de passer <code>this</code> existent&nbsp;:</p>
<table class="fullwidth-table">
 <tbody>
  <tr>
   <td class="header">Type</td>
   <td class="header">Déclenché par</td>
   <td class="header"><code>this</code></td>
  </tr>
  <tr>
   <td>appel de méthode</td>
   <td><code>objet.méthode(arg1, arg2)</code></td>
   <td><code>objet</code></td>
  </tr>
  <tr>
   <td><a href="/fr/docs/Web/JavaScript/Reference/Objets/Function/call">La méthode <code>call</code> de <code>Function</code></a></td>
   <td><code>fonction.call(objet, arg1, arg2)</code></td>
   <td><code>objet</code></td>
  </tr>
  <tr>
   <td><a href="/fr/docs/Web/JavaScript/Reference/Objets/Function/apply">La méthode <code>apply</code> de <code>Function</code></a></td>
   <td><code>fonction.apply(objet, {{ mediawiki.external('arg1, arg2') }})</code></td>
   <td><code>objet</code></td>
  </tr>
  <tr>
   <td>Gestion d'un <a href="/fr/docs/DOM/event">évènement DOM</a></td>
   <td>un évènement</td>
   <td>la cible de l'évènement dont le gestionnaire est une propriété</td>
  </tr>
 </tbody>
</table>
<p>Le dernier cas (gestion d'un évènement) n'est en réalité pas intrinsèque à JavaScript. Les évènements font partie du <a href="/fr/docs/DOM">DOM</a>, 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.)</p>
<p>Si aucune de ces manières n'est utilisée, c'est l'objet global qui est passé comme objet de contexte.</p>
<h3 id="Liaison_de_m.C3.A9thodes" name="Liaison_de_m.C3.A9thodes">Liaison de méthodes</h3>
<p>Du fait du «&nbsp;passage&nbsp;» de <code>this</code> aux fonctions, <code>this</code> n'a pas de valeur fixe pour une fonction. Cela signifie qu'une fonction n'a pas de «&nbsp;propriétaire&nbsp;» ou de «&nbsp;parent&nbsp;», 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.</p>
<p>Pour illustrer le concept de liaison, examinons le code suivant&nbsp;:</p>
<pre class="eval">
function Voiture(marque) {
   this.marque = marque;
}
Voiture.prototype.getMarque = function() {
   return this.marque;
}
var foo = new Voiture('toyota');
alert(foo.getMarque());
</pre>
<p>Comme on peut s'y attendre, ceci affiche «&nbsp;toyota&nbsp;».</p>
<pre class="eval">
var marque = 'pas une voiture';
var bar = foo.getMarque;
bar();
</pre>
<p>De manière inattendue, ceci affichera «&nbsp;pas une voiture&nbsp;» plutôt que «&nbsp;toyota&nbsp;». Comme <code>bar()</code> n'est pas un appel de méthode, l'objet de contexte n'est pas passé. La valeur de <code>this</code> est alors par défaut l'objet global, qui est <code>window</code> dans l'environnement d'un navigateur. L'objet global, lui aussi, a une propriété appelée <code>marque</code> dont la valeur est <code>"pas une voiture"</code>. S'il n'avait pas de propriété appelée <code>marque</code>, on aurait plutôt vu s'afficher <code>"undefined"</code>.</p>
<p>Ceci indique que <code>bar</code> n'est en aucune manière lié à <code>foo</code>. Ou plutôt, que la fonction à laquelle font référence <code>bar</code> et <code>foo.getMarque</code> n'est pas liée à son «&nbsp;objet parent&nbsp;», <code>foo</code>. Un objet peut disposer d'une propriété faisant référence à la fonction, mais celle-ci n'
 <i>
  appartient</i>
 pas à l'objet. La distinction entre méthodes et fonctions se fait uniquement au moment de l'appel&nbsp;: les
 <i>
  appels de méthode</i>
 passent l'«&nbsp;objet parent&nbsp;» comme valeur de <code>this</code>, tandis que les
 <i>
  appels de fonctions</i>
 passent l'objet global en tant que <code>this</code>.</p>
<p>Spécifiquement, la valeur de <code>this</code> au sein de la fonction n'est pas automatiquement fournie par <code>foo</code>. Au lieu de cela, <code>this</code> provient de l'appel de fonction. C'est-à-dire que dans l'expression <code>foo.getMarque()</code>, <code>foo</code> est passé en tant que <code>this</code> à la fonction à laquelle fait référence <code>foo.getMarque</code>. Chacune des lignes suivantes est équivalente&nbsp;:</p>
<pre class="eval">
foo.getMarque();
bar.call(foo);
foo.getMarque.call(foo);
</pre>
<p>Cette absence de lien avec les méthodes est volontaire. Elle permet aux méthodes d'être «&nbsp;partagées&nbsp;» ou «&nbsp;déplacées&nbsp;» d'un objet à l'autre. Pour faire suite à l'exemple suivant&nbsp;:</p>
<pre class="eval">
function Avion(marque) {
   this.marque = marque;
}
var avion = new Avion('airbus');
</pre>
<p><code>avion</code> n'a pas de méthode <code>getMarque</code>, mais il dispose d'une propriété <code>marque</code>, ce qui le rend compatible avec la méthode code&gt;getMarque&lt;/code&gt; de <code>Voiture</code>. Par conséquent, la fonction à laquelle <code>Voiture.prototype.getMarque</code> fait référence peut être «&nbsp;partagée&nbsp;» avec un objet construit avec <code>Avion</code> ou avec <code>Avion.prototype</code> (ce qui ajouterait la méthode à tous les objets construits avec <code>Avion</code> ):</p>
<pre class="eval">
Avion.prototype.getMarque = Voiture.prototype.getMarque;
alert(avion.getMarque());
</pre>
<p>La fonction n'est pas réellement copiée. Elle est partagée&nbsp;; <code>Avion.prototype.getMarque</code> et <code>Voiture.prototype.getMarque</code> font référence au même objet Function. Par exemple&nbsp;:</p>
<pre class="eval">
Avion.prototype.getMarque.nouvelle_propriété = 'hello';
alert(Voiture.prototype.getMarque.nouvelle_propriété);
</pre>
<p>Ce code affichera «&nbsp;hello&nbsp;», ce qui indique qu'<code>Avion.prototype.getMarque</code> et <code>Voiture.prototype.getMarque</code> ne font qu'un.</p>
<div class="note">
 <p>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 <code><a href="/fr/docs/DOM/window.setTimeout">setTimeout()</a></code> ou <code><a href="/fr/docs/DOM/element.addEventListener">addEventListener()</a></code>&nbsp;:</p>
 <pre class="eval">
setTimeout(objet.fonction, 1000); // passe la mauvaise valeur pour |this|&nbsp;!
document.addEventListener("load", objet.fonction, false); //  passe la mauvaise valeur pour |this|&nbsp;!
</pre>
 <p>Une manière simple de contourner cela est de passer une fonction anonyme comme callback</p>
 <pre class="eval">
document.addEventListener("load", function(event) { objet.fonction(event); }, false);
</pre>
 <p>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.</p>
 <p>Une autre option dans le cas d'<code>addEventListener()</code> est de passer un objet avec une méthode <code>handleEvent()</code>&nbsp;:</p>
 <pre class="eval">
var objet = {
  // ...
  handleEvent: function(e) {
    // ...
  }
}
document.addEventListener("load", objet, false)
</pre>
 <p>Dans certain cas, on peut aussi utiliser "this" à travers une variable&nbsp;: <code> </code></p>
 <pre class="eval">
var obj = this;
document.addEventListener("load", obj.fonction, false);
</pre>
 <p>&nbsp;</p>
</div>
<h3 id="Exemples" name="Exemples">Exemples</h3>
<h4 id="Exemple_:_utilisation_de_this_dans_un_gestionnaire_d.27.C3.A9v.C3.A8nement" name="Exemple_:_utilisation_de_this_dans_un_gestionnaire_d.27.C3.A9v.C3.A8nement">Exemple&nbsp;: utilisation de <code>this</code> dans un gestionnaire d'évènement</h4>
<p>Supposons qu'une fonction appelée <code>validation</code> serve à valider la propriété <code>valeur</code> d'un objet, à partir de l'objet et de bornes inférieure et supérieure pour cette valeur&nbsp;:</p>
<pre class="eval">
function validation(objet, min, max) {
   if ((objet.valeur &lt; min) || (objet.valeur &gt; max))
      alert("Valeur non valide.");
}
</pre>
<p>On pourrait appeler <code>validation</code> dans chaque gestionnaire d'évènement <code>onChange</code> des contrôles d'un formulaire, en utilisant <code>this</code> pour passer l'élément de formulaire, comme dans l'exemple suivant&nbsp;:</p>
<pre>
&lt;b&gt;Entrez un nombre entre 18 et 99&nbsp;:&lt;/b&gt;
&lt;input type="text" name="age" size="3"
   onchange="validation(this, 18, 99);"/&gt;</pre>
Revert to this revision