web-dev-qa-db-fra.com

var self = this?

L'utilisation de méthodes d'instance en tant que rappels pour les gestionnaires d'événements modifie la portée de this de "Mon instance" à "Tout ce qui vient d'appeler le rappel". Donc, mon code ressemble à ceci

function MyObject() {
  this.doSomething = function() {
    ...
  }

  var self = this
  $('#foobar').bind('click', function(){
    self.doSomethng()
    // this.doSomething() would not work here
  })
}

Cela fonctionne, mais est-ce la meilleure façon de le faire? Cela me semble étrange.

180
defnull

Cette question n'est pas spécifique à jQuery, mais spécifique à JavaScript en général. Le principal problème est de savoir "canaliser" une variable dans les fonctions intégrées. Voici l'exemple:

var abc = 1; // we want to use this variable in embedded functions

function xyz(){
  console.log(abc); // it is available here!
  function qwe(){
    console.log(abc); // it is available here too!
  }
  ...
};

Cette technique repose sur l'utilisation d'une fermeture. Mais cela ne fonctionne pas avec this, car this est une pseudo-variable qui peut changer de portée de manière dynamique:

// we want to use "this" variable in embedded functions

function xyz(){
  // "this" is different here!
  console.log(this); // not what we wanted!
  function qwe(){
    // "this" is different here too!
    console.log(this); // not what we wanted!
  }
  ...
};

Que pouvons-nous faire? Attribuez-le à une variable et utilisez-le via l'alias:

var abc = this; // we want to use this variable in embedded functions

function xyz(){
  // "this" is different here! --- but we don't care!
  console.log(abc); // now it is the right object!
  function qwe(){
    // "this" is different here too! --- but we don't care!
    console.log(abc); // it is the right object here too!
  }
  ...
};

this n'est pas unique à cet égard: arguments est l'autre pseudo-variable qui devrait être traitée de la même manière - par aliasing.

205
Eugene Lazutkin

Oui, cela semble être une norme commune. Certains codeurs utilisent eux-mêmes, d'autres m'utilisent. Il est utilisé comme référence à l'objet "réel" par opposition à l'événement.

C'est quelque chose qui m'a pris un peu de temps à obtenir vraiment, ça a l'air bizarre au début.

Je le fais habituellement tout en haut de mon objet (excusez mon code de démonstration - c'est plus conceptuel qu'autre chose et ce n'est pas une leçon sur l'excellente technique de codage):

function MyObject(){
  var me = this;

  //Events
  Click = onClick; //Allows user to override onClick event with their own

  //Event Handlers
  onClick = function(args){
    me.MyProperty = args; //Reference me, referencing this refers to onClick
    ...
    //Do other stuff
  }
}
17
BenAlabaster

Si vous effectuez ES2015 ou le script de type et ES5, vous pouvez utiliser des fonctions de flèche dans votre code. Vous ne rencontrez pas cette erreur et cela fait référence à l'étendue souhaitée de votre instance.

this.name = 'test'
myObject.doSomething(data => {
  console.log(this.name)  // this should print out 'test'
});
12
Aran Dekar
var functionX = function() {
  var self = this;
  var functionY = function(y) {
    // If we call "this" in here, we get a reference to functionY,
    // but if we call "self" (defined earlier), we get a reference to function X.
  }
}

edit: malgré, les fonctions imbriquées dans un objet prennent l'objet fenêtre globale plutôt que l'objet environnant.

10
serkan

Une solution à ce problème consiste à lier tout votre rappel à votre objet avec la méthode bind de javascript.

Vous pouvez le faire avec une méthode nommée,

function MyNamedMethod() {
  // You can now call methods on "this" here 
}

doCallBack(MyNamedMethod.bind(this)); 

Ou avec un rappel anonyme

doCallBack(function () {
  // You can now call methods on "this" here
}.bind(this));

Faire cela au lieu de recourir à var self = this Montre que la liaison de this se comporte en javascript et ne repose pas sur une référence de fermeture.

En outre, l'opérateur de flèche en gras dans ES6 est fondamentalement le même qu'un appel .bind(this) sur une fonction anonyme:

doCallback( () => {
  // You can reference "this" here now
});
4
Bart Dorsey

Je n'ai pas utilisé jQuery, mais dans une bibliothèque telle que Prototype, vous pouvez lier des fonctions à une portée spécifique. Donc, dans cet esprit, votre code ressemblerait à ceci:

 $('#foobar').ready('click', this.doSomething.bind(this));

La méthode bind renvoie une nouvelle fonction qui appelle la méthode d'origine avec l'étendue que vous avez spécifiée.

3
neonski

Ajoutez simplement à cela que dans ES6 à cause de fonctions de flèche vous ne devriez pas avoir à le faire car ils capturent la valeur this.

2
aug

Je pense que cela dépend de ce que vous allez faire dans votre fonction doSomething. Si vous souhaitez accéder à MyObject propriétés à l'aide de ce mot clé, vous devez l'utiliser. Mais je pense que le fragment de code suivant fonctionnera aussi si vous ne faites pas de choses spéciales en utilisant les propriétés object(MyObject).

function doSomething(){
  .........
}

$("#foobar").ready('click', function(){

});
1
Milinda