web-dev-qa-db-fra.com

Pourquoi JavaScript bind () est-il nécessaire?

Le problème de l'exemple 1 est "ceci" faisant référence au nom global au lieu de l'objet myName.

Je comprends l'utilisation de bind () pour définir la valeur de this sur un objet spécifique. Le problème de l'exemple 1 est donc résolu, mais pourquoi ce problème se produit-il en premier lieu? Est-ce juste la façon dont Javascript a été créé? 

Je me demande également pourquoi l'exemple 3 résout le problème et la différence entre les exemples 2 et 3. 

this.name = "John"

var myName = {
  name: "Tom",
  getName: function() {
    return this.name
  }
}

var storeMyName = myName.getName; // example 1
var storeMyName2 = myName.getName.bind(myName); // example 2
var storeMyName3 = myName.getName(); // example 3

console.log("example 1: " + storeMyName()); // doesn't work
console.log("example 2: " + storeMyName2()); // works
console.log("example 3: " + storeMyName3); // works

40
Tom

Pourquoi JavaScript bind () est-il nécessaire?

La valeur de this est déterminée par comment une fonction est appelée. Si c'est vous qui appelle la fonction, il n'est généralement pas nécessaire d'utiliser .bind, car vous avez le contrôle sur la façon d'appeler la fonction, et donc sa valeur this.

Cependant, c’est souvent pas vous qui appelez la fonction. Les fonctions sont transmises à d'autres fonctions en tant que callbacks et gestionnaires d'événements. Ils sont appelés par le code other et vous n’avez aucun contrôle sur comment la fonction est appelée et vous ne pouvez donc pas contrôler ce que this désignera.

Si votre fonction nécessite que this soit définie sur une valeur spécifique et que vous n'êtes pas celui qui appelle la fonction, vous devez .bind la fonction avec une valeur this spécifique.

En d'autres termes: .bind vous permet de définir la valeur de this sans appeler la fonction now.

Voici une comparaison des fonctions de référence/appelantes:

                    +-------------------+-------------------+
                    |                   |                   |
                    |      time of      |       time of     |
                    |function execution |    this binding   |
                    |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|  function object  |      future       |      future       |
|         f         |                   |                   |
|                   |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|   function call   |       now         |        now        |
|        f()        |                   |                   |
|                   |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|     f.call()      |       now         |        now        |
|     f.apply()     |                   |                   |
|                   |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|     f.bind()      |      future       |        now        |
|                   |                   |                   |
+-------------------+-------------------+-------------------+

Je me demande également pourquoi l'exemple 3 résout le problème et la différence entre les exemples 2 et 3.

Les exemples 1/2 et 3 ne pourraient pas être plus différents. storeMyName et storeMyName2 contiennent functions, qui seront appelés ultérieurement, alors que storeMyName3 contient le résultat de l'appel de myName.getName()à ce moment-là.


Matériel de lecture supplémentaire:

58
Felix Kling

La méthode bind() crée une nouvelle fonction qui, lorsqu'elle est appelée, a pour mot clé this la valeur fournie, avec une séquence d'arguments donnée précédant tous ceux fournis lors de l'appel de la nouvelle fonction.

Ainsi, lorsque vous exécutez var storeMyName = myName.getName; la première fois, il faut la variable globale name (this.name = "John")

Lorsque vous utilisez la fonction bind(), elle commence à faire référence au nom défini dans la fermeture actuelle (myName dans ce cas) et imprime donc Tom

Troisième fois, puisque la fonction est appelée immédiatement, son étendue se trouve dans son propre objet local et imprime donc la valeur dans la fermeture Tom

6
mrid

Bind est le mécanisme par lequel vous pouvez changer le contexte d'exécution (ici votre contexte par défaut est global).

Basé sur votre exemple - 

var storeMyName = myName.getName;

A partir de la ligne ci-dessus, vous exécutez la fonction storeMyName dans un contexte global. Ainsi, pour cette exécution, this.name sera la ligne du haut (c'est-à-dire globale/"John").

var storeMyName2 = myName.getName.bind(myName);

Pour la ligne ci-dessus, vous êtes explicitement changez le contexte d'exécution de la fonction storeMyName2 (en disant que je ne veux pas exécuter cette fonction en tant que fonction globale, je veux exécuter cette fonction dans le contexte de l'objet myName, donc dans ce cas this.name sera "Tom")

var storeMyName3 = myName.getName(); // example 3

Et pour cette ligne ci-dessus, vous exécutez juste une fonction sur le contexte d'objet myName. Plus important encore, vous n'exécutez pas le storeMyName3 et c'est pourquoi son contexte n'est pas global.

0
Dhruv

Une analogie que j’aime bien, que je n’ai jamais vue nulle part ailleurs: Disons que vous avez un objet foo avec une fonction bar . Lorsque vous liez la fonction bar à une autre variable est plus commun avec les callbacks), vous ne liez/passez pas la fonction avec son objet englobant mais seulement avec la fonction "nude" . Ainsi, avec la fonction "nude", this désigne l’objet global.

Une petite démo

var foo = "global foo"; //foo set on the global object
var a = {foo : "object foo", bar : function(){return this.foo;}};
var bound = a.bar;
console.log(bound());//returns "global foo", not "object foo"

bound il suffit de pointer vers le function(){return this.foo;}

0
Vincent J