Le mot-clé this de JavaScript est un concept fondamental qui laisse souvent perplexe les développeurs débutants et chevronnés. Sa nature dynamique peut conduire à des comportements inattendus si elle n’est pas bien comprise. Ce guide complet vise à démystifier cela, en explorant ses différents contextes, nuances et meilleures pratiques, complété par des exemples illustratifs et des problèmes difficiles pour consolider votre compréhension.
En JavaScript, this est un mot-clé qui fait référence à l'objet à partir duquel le code actuel est exécuté. Contrairement à certains autres langages de programmation où cela est lié statiquement, celui de JavaScript est déterminé dynamiquement en fonction de la façon dont une fonction est appelée.
Lorsqu'il n'est à l'intérieur d'aucune fonction, cela fait référence à l'objet global.
Exemple
console.log(this === window); // true (in browser) console.log(this === global); // true (in Node.js)
Remarque : En mode strict (« use strict » ;), ceci dans le contexte global reste l'objet global.
Dans les fonctions régulières, cela est déterminé par la manière dont la fonction est appelée.
Exemple :
function showThis() { console.log(this); } showThis(); // Window object (in browser) or global (in Node.js)
Exemple
const person = { name: 'Alice', greet: function() { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm Alice"
Nous pouvons utiliser call, apply ou bind pour définir explicitement cela.
function greet() { console.log(`Hello, I'm ${this.name}`); } const person = { name: 'Bob' }; greet.call(person); // "Hello, I'm Bob"
Les fonctions fléchées ont un lexical this, ce qui signifie qu'elles héritent de celui-ci de la portée environnante au moment de leur création.
Exemple
const person = { name: 'Charlie', greet: () => { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm undefined" (or global name if defined)
Explication : Puisque les fonctions fléchées n'ont pas leur propre this, cela fait référence à l'objet global, pas à l'objet personne.
Utilisation correcte avec les fonctions fléchées :
const person = { name: 'Dana', greet: function() { const inner = () => { console.log(`Hello, I'm ${this.name}`); }; inner(); } }; person.greet(); // "Hello, I'm Dana"
Aspect difficile : Si une méthode est assignée à une variable et appelée, elle peut perdre son contexte prévu.
Exemple
const calculator = { value: 0, add: function(num) { this.value += num; return this.value; } }; console.log(calculator.add(5)); // 5 console.log(calculator.add(10)); // 15 const addFunction = calculator.add; console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)
Lorsqu'une fonction est utilisée comme constructeur avec le mot-clé new, cela fait référence à l'instance nouvellement créée.
console.log(this === window); // true (in browser) console.log(this === global); // true (in Node.js)
Remarques importantes :
• Si new n'est pas utilisé, cela peut faire référence à l'objet global ou être indéfini en mode strict.
• Les constructeurs mettent généralement la première lettre en majuscule pour les distinguer des fonctions normales.
Dans les gestionnaires d'événements, cela fait référence à l'élément qui a reçu l'événement.
Exemple
function showThis() { console.log(this); } showThis(); // Window object (in browser) or global (in Node.js)
JavaScript fournit des méthodes pour définir explicitement la valeur de this :
const person = { name: 'Alice', greet: function() { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm Alice"
function greet() { console.log(`Hello, I'm ${this.name}`); } const person = { name: 'Bob' }; greet.call(person); // "Hello, I'm Bob"
const person = { name: 'Charlie', greet: () => { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm undefined" (or global name if defined)
Cas d'utilisation :
ES6 a introduit des classes, qui fournissent une syntaxe plus claire pour les fonctions et méthodes du constructeur. Dans les méthodes de classe, cela fait référence à l'instance.
Exemple :
const person = { name: 'Dana', greet: function() { const inner = () => { console.log(`Hello, I'm ${this.name}`); }; inner(); } }; person.greet(); // "Hello, I'm Dana"
Fonctions des flèches dans les classes :
Les fonctions fléchées peuvent être utilisées pour que les méthodes héritent de cela du contexte de classe, utile pour les rappels.
const calculator = { value: 0, add: function(num) { this.value += num; return this.value; } }; console.log(calculator.add(5)); // 5 console.log(calculator.add(10)); // 15 const addFunction = calculator.add; console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)
Lors du passage de méthodes en tant que rappels, le contexte d'origine peut être perdu.
Problème
function Person(name) { this.name = name; } const alice = new Person('Alice'); console.log(alice.name); // "Alice"
Solution
Utilisez bind pour préserver le contexte.
<button> <p><strong>Arrow Function Caveat:</strong><br> Using arrow functions in event handlers can lead to this referring to the surrounding scope instead of the event target.<br> <strong>Example:</strong><br> </p> <pre class="brush:php;toolbar:false">button.addEventListener('click', () => { console.log(this); // Global object or enclosing scope });
Les fonctions fléchées n'ont pas leur propre this, ce qui peut entraîner un comportement inattendu lorsqu'elles sont utilisées comme méthodes.
Problème
function greet(greeting) { console.log(`${greeting}, I'm ${this.name}`); } const person = { name: 'Eve' }; greet.call(person, 'Hello'); // "Hello, I'm Eve"
Solution
Utilisez des fonctions régulières pour les méthodes objet.
greet.apply(person, ['Hi']); // "Hi, I'm Eve"
La définition involontaire de propriétés sur l'objet global peut entraîner des bugs.
Problème
const boundGreet = greet.bind(person); boundGreet('Hey'); // "Hey, I'm Eve"
Solution
Utilisez le mode strict ou une liaison appropriée.
class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } const dog = new Animal('Dog'); dog.speak(); // "Dog makes a noise."
Dans les fonctions imbriquées, this ne peut pas faire référence au this externe. Les solutions incluent l'utilisation de fonctions fléchées ou leur stockage dans une variable.
Exemple avec la fonction flèche :
class Person { constructor(name) { this.name = name; } greet = () => { console.log(`Hello, I'm ${this.name}`); } } const john = new Person('John'); john.greet(); // "Hello, I'm John"
Exemple avec variable :
const obj = { name: 'Object', getName: function() { return this.name; } }; const getName = obj.getName; console.log(getName()); // undefined or global name
Lors de l'utilisation de prototypes, cela fait référence à l'instance.
console.log(this === window); // true (in browser) console.log(this === global); // true (in Node.js)
Le mot-clé this en JavaScript est une fonctionnalité polyvalente et puissante qui, lorsqu'elle est correctement comprise, peut considérablement améliorer vos capacités de codage.
Pour vraiment consolider votre compréhension de cela, abordez les problèmes difficiles suivants. Chaque problème est conçu pour tester différents aspects et cas extrêmes du mot-clé this en JavaScript. Des solutions à la fin.
function showThis() { console.log(this); } showThis(); // Window object (in browser) or global (in Node.js)
const person = { name: 'Alice', greet: function() { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm Alice"
function greet() { console.log(`Hello, I'm ${this.name}`); } const person = { name: 'Bob' }; greet.call(person); // "Hello, I'm Bob"
const person = { name: 'Charlie', greet: () => { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm undefined" (or global name if defined)
const person = { name: 'Dana', greet: function() { const inner = () => { console.log(`Hello, I'm ${this.name}`); }; inner(); } }; person.greet(); // "Hello, I'm Dana"
const calculator = { value: 0, add: function(num) { this.value += num; return this.value; } }; console.log(calculator.add(5)); // 5 console.log(calculator.add(10)); // 15 const addFunction = calculator.add; console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)
function Person(name) { this.name = name; } const alice = new Person('Alice'); console.log(alice.name); // "Alice"
<button> <p><strong>Arrow Function Caveat:</strong><br> Using arrow functions in event handlers can lead to this referring to the surrounding scope instead of the event target.<br> <strong>Example:</strong><br> </p> <pre class="brush:php;toolbar:false">button.addEventListener('click', () => { console.log(this); // Global object or enclosing scope });
function greet(greeting) { console.log(`${greeting}, I'm ${this.name}`); } const person = { name: 'Eve' }; greet.call(person, 'Hello'); // "Hello, I'm Eve"
Lorsque getName est attribué à une variable et appelé sans aucun contexte d'objet, la valeur par défaut est l'objet global. En mode non strict, this.name fait référence au nom global, qui est « Global ». En mode strict, cela ne serait pas défini, ce qui entraînerait une erreur.
greet.apply(person, ['Hi']); // "Hi, I'm Eve"
Les fonctions fléchées n'ont pas leur propre ceci ; ils en héritent du périmètre environnant. Dans ce cas, la portée environnante est le contexte global, où this.name est « Global ».
const boundGreet = greet.bind(person); boundGreet('Hey'); // "Hey, I'm Eve"
Dans le rappel setInterval, this fait référence à l'objet global (ou n'est pas défini en mode strict). Ainsi, this.seconds incrémente window.seconds ou génère une erreur en mode strict. Le timer.seconds reste 0.
class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } const dog = new Animal('Dog'); dog.speak(); // "Dog makes a noise."
Après avoir lié retrieveX au module, l'appel deboundGetX() le définit correctement sur module.
class Person { constructor(name) { this.name = name; } greet = () => { console.log(`Hello, I'm ${this.name}`); } } const john = new Person('John'); john.greet(); // "Hello, I'm John"
La fonction fléchée getModel hérite de cela du constructeur, qui fait référence à l'instance de voiture nouvellement créée.
const obj = { name: 'Object', getName: function() { return this.name; } }; const getName = obj.getName; console.log(getName()); // undefined or global name
Dans les gestionnaires d'événements utilisant des fonctions régulières, cela fait référence à l'élément DOM qui a reçu l'événement, qui est le bouton. Étant donné que le bouton n'a pas de propriété name, this.name n'est pas défini.
console.log(this === window); // true (in browser) console.log(this === global); // true (in Node.js)
function showThis() { console.log(this); } showThis(); // Window object (in browser) or global (in Node.js)
Dans le constructeur Promise, this fait référence à l'objet global (ou n'est pas défini en mode strict). Ainsi, this.value n'est pas défini (ou provoque une erreur en mode strict).
const person = { name: 'Alice', greet: function() { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm Alice"
La fonction multiplier est liée au premier argument a comme 2. Lorsque double(5) est appelé, elle calcule effectivement multiplier(2, 5).
function greet() { console.log(`Hello, I'm ${this.name}`); } const person = { name: 'Bob' }; greet.call(person); // "Hello, I'm Bob"
Dans la méthode speak de la classe Dog, le rappel setTimeout est une fonction régulière. Ainsi, ceci à l'intérieur du rappel fait référence à l'objet global, et non à l'instance du chien. this.name est « non défini » ou provoque une erreur si le nom n’est pas défini globalement.
const person = { name: 'Charlie', greet: () => { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm undefined" (or global name if defined)
Pour résoudre ce problème, utilisez une fonction flèche :
const person = { name: 'Dana', greet: function() { const inner = () => { console.log(`Hello, I'm ${this.name}`); }; inner(); } }; person.greet(); // "Hello, I'm Dana"
Maintenant, il enregistre correctement :
const calculator = { value: 0, add: function(num) { this.value += num; return this.value; } }; console.log(calculator.add(5)); // 5 console.log(calculator.add(10)); // 15 const addFunction = calculator.add; console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!