JavaScript et l’erreur : this.____ is not a function


le mot clé « this » est un mot clé spécial qui fait référence à l’objet courant dans lequel il est utilisé. Le mot clé this peut être utilisé dans une fonction, un objet, ou même seule, puisque le code javascript que vous écrivez se trouve dans l’objet Window représentant l’onglet de votre navigateur web, this dépendra dans ce cas du contexte de l’objet Window.

this dans le contexte global

Quand this est utilisé dans la feuille JavaScript sans appartenir ni à un objet, une variable ou une fonction, on dit qu’il est utilisé dans le contexte global.

console.log(this);

dans ce cas, this, fera référence à l’objet window.

Window {window: Window, self: Window, document: document, ......

this dans une fonction

Dans le cas ou this est utilisé dans une fonction, il fera aussi référence à l’objet window.

function afficherThis(){
    console.log(this);
}

afficherThis();

résultat :

Window {window: Window, self: Window, document: document, ......

this dans un objet créé et instancié

En revanche, si on utilise le mot clé this dans un objet, celui-ci fera référence à l’objet créé lui-même. Il est d’ailleurs couramment utilisé pour créer nos propriétés et nos méthodes de classe.

class personne{

    constructor(){
        this.nom = "Dor";
        this.prenom = "Louis";
        console.log(this);
    }
}
let person = new Personne();

resultat :

 Personne {prenom: 'Louis', nom: 'Dor'}

Pourquoi this fait référence à l’objet window

En général, on exécute du JavaScript dans la fenêtre de notre navigateur. Cette fenêtre est représentée par l’objet window. L’objet window est un objet global qui peut être accessible quasiment partout dans notre code.

console.log(window)

Tout ce qui se trouve au premier niveau de la page se trouve dans l’objet window. Cela peut être une déclaration de variable, une déclaration de fonction ou encore un objet.

// => window.bonjour ?
var bonjour = "bonjour" 

// => window.coucou
function coucou(){
    return "bonjour";
}

// => window.coucouObj
let coucouObj = {
    salutation : "bonjour",
}

L’erreur : Uncaught TypeError: this.____ is not a function

Alors forcement, avec un comportement aussi dispersé, this va nous offrir son lot de fourberies.

var afficheThis = function(){
  console.log(this);
}

class Personne{
  
  constructor(){
    this.prenom = "Louis";
    this.nom = "Dor";
  }
  
  afficherThis(){
    
    // retourne l'objet "button" parent de this
    let button = document.getElementById('js-button');
    button.addEventListener('click', function(){
      console.log(this);
    });
    
    // retourne l'objet "window" parent de la fonction setTimeout
    setTimeout(function(){ 
      console.log(this);
    }, 1500);
  }
  
}

let person = new Personne();
person.afficherThis();

Comment appeler nos méthodes sans avoir accès à « this » !?

Mais quand on a besoin de déclarer un évènement contenant une fonction anonyme à l’intérieur d’une méthode de classe, il se passe quelque chose d’étrange.

Méthode 1 : Passage par référence

Pour pouvoir utiliser le « this » de notre objet dans lequel on travaille, il suffit de passer la référence de ce mot clé dans une variable :

let _this = this;

De cette manière, on pourra utiliser nos méthode et propriété à l’aide de la variable _this à l’intérieur de nos fonctions problématiques. Cette méthode n’est pas très esthétique, mais possède les avantages suivant :

var afficheThis = function(){
  console.log(this);
}

class Personne{
  
  constructor(){
    this.prenom = "Louis";
    this.nom = "Dor";
  }
  
  afficherThis(){
    
    let _this = this;
    
    let button = document.getElementById('js-button');
    button.addEventListener('click', function(){
      console.log(_this);
    });
    
    setTimeout(function(){ 
      console.log(_this);
    }, 1500);
  }
  
}

let person = new Personne();
person.afficherThis();

Methode 2 : Bind

On peut aussi lier le contexte que l’on souhaite directement au mot clé « this » à l’intérieur de nos fonctions problématique. Pour cela on utilise bind(). À l’aide de « bind », la fonction originale n’est pas modifiée, mais une nouvelle fonction est créée avec le contexte lié. C’est une méthode plutôt esthétique. Il faudra tout de même faire attention à deux points précis :

var afficheThis = function(){
  console.log(this);
}

class Personne{
  
  constructor(){
    this.prenom = "Louis";
    this.nom = "Dor";
  }
  
  afficherThis(){
    
    let _this = this;
    
    let button = document.getElementById('js-button');
    button.addEventListener('click', function(){
      console.log(this);
    }.bind(this));
    
    setTimeout(function(){ 
      console.log(this);
    }.bind(this), 1500);
  }
  
}

let person = new Personne();
person.afficherThis();