Ce que vous devez savoir this
this(aka "le contexte") est un mot-clé spécial à l'intérieur de chaque fonction et sa valeur ne dépend que de la façon dont la fonction a été appelée, et non de la manière / quand / où elle a été définie. Il n'est pas affecté par les portées lexicales comme les autres variables (à l'exception des fonctions fléchées, voir ci-dessous). Voici quelques exemples:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Pour en savoir plus this, consultez la documentation MDN .
Comment se référer à la bonne this
Ne pas utiliser this
En fait, vous ne voulez pas accéder thisen particulier, mais à l'objet auquel il se réfère . C'est pourquoi une solution simple consiste à créer simplement une nouvelle variable qui fait également référence à cet objet. La variable peut avoir n'importe quel nom, mais les plus courants sont selfet that.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
Étant donné qu'il selfs'agit d'une variable normale, elle obéit aux règles de portée lexicale et est accessible à l'intérieur du rappel. Cela a également l'avantage que vous pouvez accéder à la thisvaleur du rappel lui-même.
Ensemble explicite thisdu rappel - partie 1
Il peut sembler que vous n'avez aucun contrôle sur la valeur de thiscar sa valeur est définie automatiquement, mais ce n'est en fait pas le cas.
Chaque fonction a la méthode .bind [docs] , qui retourne une nouvelle fonction thisliée à une valeur. La fonction a exactement le même comportement que celui que vous avez appelé .bind, seulement celui que thisvous avez défini. Peu importe comment ou quand cette fonction est appelée, elle thisfera toujours référence à la valeur transmise.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
Dans ce cas, nous à lier de la fonction de rappel thisà la valeur de MyConstructor« s this.
Remarque: lors de la liaison du contexte pour jQuery, utilisez plutôt jQuery.proxy [docs] . La raison pour cela est que vous n'avez pas besoin de stocker la référence à la fonction lors de la dissociation d'un rappel d'événement. jQuery gère cela en interne.
ECMAScript 6 introduit les fonctions flèches , qui peuvent être considérées comme des fonctions lambda. Ils n'ont pas leur propre thisreliure. Au lieu de cela, thisest recherché dans la portée comme une variable normale. Cela signifie que vous n'avez pas à appeler .bind. Ce n'est pas le seul comportement spécial qu'ils ont, veuillez vous référer à la documentation MDN pour plus d'informations.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
Ensemble thisdu rappel - partie 2
Certaines fonctions / méthodes qui acceptent les rappels acceptent également une valeur à laquelle les rappels thisdoivent se référer. C'est fondamentalement la même chose que de le lier vous-même, mais la fonction / méthode le fait pour vous. Array#map [docs] est une telle méthode. Sa signature est:
array.map(callback[, thisArg])
Le premier argument est le rappel et le deuxième argument est la valeur à laquelle il thisfaut se référer. Voici un exemple artificiel:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
Remarque: La possibilité de transmettre ou non une valeur pour thisest généralement mentionnée dans la documentation de cette fonction / méthode. Par exemple, la $.ajaxméthode de jQuery [docs] décrit une option appelée context:
Cet objet deviendra le contexte de tous les rappels liés à Ajax.
Problème courant: utilisation de méthodes d'objet comme rappels / gestionnaires d'événements
Une autre manifestation courante de ce problème est lorsqu'une méthode objet est utilisée comme gestionnaire de rappel / événement. Les fonctions sont des citoyens de première classe en JavaScript et le terme "méthode" n'est qu'un terme familier pour une fonction qui est une valeur d'une propriété d'objet. Mais cette fonction n'a pas de lien spécifique vers son objet "contenant".
Prenons l'exemple suivant:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
La fonction this.methodest affectée en tant que gestionnaire d'événements click, mais si l' document.bodyon clique sur, la valeur consignée sera undefined, car à l'intérieur du gestionnaire d'événements, thisfait référence à document.body, pas à l'instance de Foo.
Comme déjà mentionné au début, ce qui thisfait référence dépend de la façon dont la fonction est appelée , et non de la façon dont elle est définie .
Si le code était le suivant, il pourrait être plus évident que la fonction n'a pas de référence implicite à l'objet:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
La solution est la même que celle mentionnée ci-dessus: si disponible, utilisez .bindpour lier explicitementthis à une valeur spécifique
document.body.onclick = this.method.bind(this);
ou appeler explicitement la fonction en tant que "méthode" de l'objet, en utilisant une fonction anonyme comme gestionnaire de rappel / événement et attribuer l'objet (this ) à une autre variable:
var self = this;
document.body.onclick = function() {
self.method();
};
ou utilisez une fonction flèche:
document.body.onclick = () => this.method();