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 this
en 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 self
et that
.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
Étant donné qu'il self
s'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 this
valeur du rappel lui-même.
Ensemble explicite this
du rappel - partie 1
Il peut sembler que vous n'avez aucun contrôle sur la valeur de this
car 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 this
liée à une valeur. La fonction a exactement le même comportement que celui que vous avez appelé .bind
, seulement celui que this
vous avez défini. Peu importe comment ou quand cette fonction est appelée, elle this
fera 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 this
reliure. Au lieu de cela, this
est 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 this
du rappel - partie 2
Certaines fonctions / méthodes qui acceptent les rappels acceptent également une valeur à laquelle les rappels this
doivent 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 this
faut 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 this
est généralement mentionnée dans la documentation de cette fonction / méthode. Par exemple, la $.ajax
mé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.method
est affectée en tant que gestionnaire d'événements click, mais si l' document.body
on clique sur, la valeur consignée sera undefined
, car à l'intérieur du gestionnaire d'événements, this
fait référence à document.body
, pas à l'instance de Foo
.
Comme déjà mentionné au début, ce qui this
fait 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 .bind
pour 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();