
JavaScript : Comprendre et utiliser call, apply et bind
#1
D'où sortent call, apply et bind ?
Une précision préliminaire au niveau du vocabulaire. Dans ce tuto j'utilise indifféremment les mots instance ou objet car ils veulent dire la même chose et j'utilise aussi indifféremment les mots référence ou pointeur car ils veulent dire la même chose.
Je vais prendre la console et je vais déclarer par exemple une fonction que je vais appeler calculerSomme
. Si je fais un console.log
de calculerSomme
je vois la fonction. Maintenant si je fais un console.dir
je vois l'objet Function
. Maintenant je déploie et je peux voir que call
, apply
et bind
sont des méthodes qui se trouvent dans le prototype du constructeur Function
. Donc là c'est le moment de vous souvenir qu'en JavaScript les fonctions sont des objets si vous voulez vous y retrouver. Sinon ça coince car là vous vous demandez d'où sortent ce prototype et ces méthodes call
, apply
ou bind
qui se trouvent dedans.
A quoi vont servir ces méthodes ? Elles vont servir à affecter la valeur de this
au moment de l'appel d'une fonction.

#2
Comprendre et utiliser call ou apply
Mieux vaut faire un exemple plutôt que de se lancer dans une explication.
- Je vais déclarer un objet
obj
avec une propriétésomme
initialisée à0
. - Maintenant je décide de fabriquer une fonction
calculerSomme
qui a pour objectif de calculer la somme de ses arguments. Par contre ce que je veux c'est utiliserthis
pour passerobj
à cette fonction. De cette manière je vais pouvoir vous montrer que l'on peux affecterthis
. (* Pour faire ce calcul je pourrais évidemment passerobj
en argument decalculerSomme
ou créer une méthode dansobj
mais ce n'est pas l'objectif de cet exemple.) - Pour que
this
soit égal àobj
dans la fonctioncalculerSomme
je me sers de la méthodecall
et je lui passe en argumentobj
suivit des arguments que je veux passer àcalculerSomme
.

Ci-dessous, ce qu'il faut comprendre, c'est que le calculerSomme.call(obj,2,4,6)
est équivalent à un calculerSomme(2,4,6)
avec un obj
qui est affecté à this
et les arguments 2,4,6
qui sont affectées à ...data
.

Petite précision : étant donné que this
reçoit la valeur de obj
qui est un pointeur, les deux pointeront sur le même objet en mémoire c'est à dire l'objet qui contient la propriété somme
.

Maintenant je passe à un autre cas de figure. Si dans notre exemple, les données à ajouter s'étaient présentées sous la forme d'un tableau, et bien vous auriez eu avantage à utiliser apply
. Pourquoi ? En fait apply
fonctionne strictement de la même manière que call
mais prend la liste des arguments à passer à la fonction sous la forme d'un tableau. Donc si vous avez un tableau à disposition et bien vous prenez apply
plutôt que call
tout simplement !
#3
Comprendre et utiliser bind
La méthode bind
est une autre façon d'affecter this
. L'avantage avec bind
c'est que les choses se font en deux étapes :
- Dans un premier temps je vais appeler
bind
. Je vais lui passer en argument l'objet sur lequel je veux que pointethis
donc iciobj
. LecalculerSomme.bind(obj)
va me renvoyer une copie de la fonctioncalculerSomme
avec unthis
de correctement géré. - Dans un deuxième temps c'est cette copie que je vais invoquer et je vais lui passer les arguments.


#4
Utiliser bind dans les callback
Les appels à la méthode bind
sont très utilisés dans les requêtes asynchrones. Dans ce cas le bind
est utilisé au niveau de la fonction callback pour faire en sorte évidemment que le callback s'exécute avec une valeur de this
qui lui convienne.
Pourquoi le callback est-il un cas typique d'utilisation du bind ? Et bien parce qu'il correspond à une utilisation en deux temps :
- Dans un premier temps on a le passage d'une fonctionnalité en argument d'un traitement asynchrone. Ca c'est une étape qui correspond au passage du callback en argument.
- Dans un deuxième temps on a l'exécution de ce traitement. Ca c'est l'étape qui correspond à l'invocation du callback.
Je vais reprendre l'exemple d'un gestionnaire d'événement sur lequel j'ai déjà travaillé dans un autre tuto de manière à pouvoir un peu plus le détailler.
Dans l'exemple ci-dessous, je déclare une classe, je déclare sa fonction constructeur, je lui ajoute une propriété click
qui est un booléen que j'initialise à la valeur false
. Je crée la méthode set
qui servira à placer la valeur de click
à true
. Ensuite je crée un objet en instanciant la classe. Le but du truc c'est de mémoriser le fait qu'il y a eu un click
sur le bouton.
On peut voir dans le tuto dédié à this
que si je passe la méthode obj.set
en tant que callback de addEventListener
alors obj.set
s'exécute avec un this
qui a la valeur but
. Dans ces conditions et de manière à ce que this
soit correctement positionné je vais faire un obj.set.bind(obj)
.
Donc dans un premier temps j'obtiens avec mon bind
une copie de obj.set
avec le this
de positionné sur obj
. Et dans un deuxième temps la méthode obj.set
est invoquée dans les conditions que je souhaite au niveau du gestionnaire d'événement.
bind
