Javascript call () & apply () vs bind ()?

Je sais déjà que l' apply et l' call sont des fonctions similaires qui définissent this (contexte d'une fonction).

La différence est avec la façon dont nous envoyons les arguments (manuel vs tableau)

Question:

Mais quand dois-je utiliser la méthode bind() ?

 var obj = { x: 81, getX: function() { return this.x; } }; alert(obj.getX.bind(obj)()); alert(obj.getX.call(obj)); alert(obj.getX.apply(obj)); 

Jsbin

Utilisez .bind() lorsque vous souhaitez que cette fonction soit appelée avec un certain contexte, utile dans les événements. Utilisez .call() ou .apply() lorsque vous souhaitez appeler la fonction immédiatement et modifier le contexte.

Appelez / appliquez une appel à la fonction immédiatement, alors que bind renvoie une fonction qui, lorsqu'elle sera exécutée plus tard, aura le contexte correct configuré pour appeler la fonction d'origine. De cette façon, vous pouvez maintenir le contexte dans les rappels et les événements asynchrones.

Je le fais beaucoup:

 function MyObject(element) { this.elm = element; element.addEventListener('click', this.onClick.bind(this), false); }; MyObject.prototype.onClick = function(e) { var t=this; //do something with [t]... //without bind the context of this function wouldn't be a MyObject //instance as you would normally expect. }; 

Je l'utilise largement dans Node.js pour les retours de rappel asynchrones auxquels je souhaite transmettre une méthode de membre, mais je veux toujours que le contexte soit l'instance qui a commencé l'action asynchrone.

Une simple et naïve implémentation de bind serait comme:

 Function.prototype.bind = function(ctx) { var fn = this; return function() { fn.apply(ctx, arguments); }; }; 

Il y a plus (comme passer d'autres args), mais vous pouvez en lire plus et voir la mise en œuvre réelle sur le MDN .

J'espère que cela t'aides.

Ils attachent tous ceci à la fonction (ou à l'objet) et la différence est dans l'invocation de la fonction (voir ci-dessous).

L'appel attache ceci en fonction et exécute la fonction immédiatement:

 var person = { name: "James Smith", hello: function(thing) { console.log(this.name + " says hello " + thing); } } person.hello("world"); // output: "James Smith says hello world" person.hello.call({ name: "Jim Smith" }, "world"); // output: "Jim Smith says hello world" 

Bind attache ceci en fonction et il doit être invoqué séparément comme ceci:

 var person = { name: "James Smith", hello: function(thing) { console.log(this.name + " says hello " + thing); } } person.hello("world"); // output: "James Smith says hello world" var helloFunc = person.hello.bind({ name: "Jim Smith" }); helloFunc("world"); // output: Jim Smith says hello world" 

Ou comme ceci:

 ... var helloFunc = person.hello.bind({ name: "Jim Smith" }, "world"); helloFunc(); // output: Jim Smith says hello world" 

Appliquer est similaire à l' appel, sauf qu'il faut un objet semblable à un tableau au lieu d'énumérer les arguments un à la fois:

 function personContainer() { var person = { name: "James Smith", hello: function() { console.log(this.name + " says hello " + arguments[1]); } } person.hello.apply(person, arguments); } personContainer("world", "mars"); // output: "James Smith says hello mars", note: arguments[0] = "world" , arguments[1] = "mars" 

Il permet de définir la valeur indépendante de la façon dont la fonction est appelée. Ceci est très utile lorsque vous travaillez avec des rappels:

  function sayHello(){ alert(this.message); } var obj = { message : "hello" }; setTimeout(sayHello.bind(obj), 1000); 

Pour atteindre le même résultat avec l' call il ressemblerait à ceci:

  function sayHello(){ alert(this.message); } var obj = { message : "hello" }; setTimeout(function(){sayHello.call(obj)}, 1000); 

Supposons que nous avons une fonction de multiplication

 function multiplication(a,b){ console.log(a*b); } 

Permet de créer des fonctions standard en utilisant bind

var multiby2 = multiplication.bind(this,2);

Maintenant, multiby2 (b) est égal à la multiplication (2, b);

 multiby2(3); //6 multiby2(4); //8 

Que faire si je passe les deux paramètres dans bind

 var getSixAlways = multiplication.bind(this,3,2); 

Maintenant getSixAlways () est égal à la multiplication (3,2);

 getSixAlways();//6 

Même le paramètre de passage passe 6; getSixAlways(12); //6

 var magicMultiplication = multiplication.bind(this); 

Cela crée une nouvelle fonction de multiplication et l'affecte à la multiplication magique.

Oh non, nous cachons la fonctionnalité de multiplication dans MagicMultiplication.

magicMultiplication renvoie une function b() blanche function b()

magicMultiplication(6,5); //30 exécution, il fonctionne bien la magicMultiplication(6,5); //30 magicMultiplication(6,5); //30

Que diriez-vous d'appeler et de postuler?

magicMultiplication.call(this,3,2); //6

magicMultiplication.apply(this,[5,2]); //10

En termes simples, bind crée la fonction, call et apply exécute la fonction alors apply s'attend à ce que les paramètres en tableau

Function.prototype.call() et Function.prototype.apply() appelent une fonction avec une donnée donnée et renvoient la valeur de retour de cette fonction.

Function.prototype.bind() , d'autre part, crée une nouvelle fonction avec une valeur donnée et renvoie cette fonction sans l'exécuter.

Donc, prenons une fonction qui ressemble à ceci:

 var logProp = function(prop) { console.log(this[prop]); }; 

Maintenant, prenons un objet qui ressemble à ceci:

 var Obj = { x : 5, y : 10 }; 

Nous pouvons lier notre fonction à notre objet comme ceci:

 Obj.log = logProp.bind(Obj); 

Maintenant, nous pouvons exécuter Obj.log n'importe où dans notre code:

 Obj.log('x'); // Output : 5 Obj.log('y'); // Output : 10 

Là où cela devient vraiment intéressant, c'est lorsque vous liez non seulement une valeur pour this , mais aussi pour son argument:

 Obj.logX = logProp.bind(Obj, 'x'); Obj.logY = logProp.bind(Obj, 'y'); 

Nous pouvons maintenant le faire:

 Obj.logX(); // Output : 5 Obj.logY(); // Output : 10 

Voici un bon article pour illustrer la différence entre bind() , apply() et call() , résumez-le comme ci-dessous.

  • bind() nous permet de définir facilement quel objet spécifique sera lié à ceci quand une fonction ou une méthode est invoquée.

     // This data variable is a global variable​ var data = [ {name:"Samantha", age:12}, {name:"Alexis", age:14} ] var user = { // local data variable​ data :[ {name:"T. Woods", age:37}, {name:"P. Mickelson", age:43} ], showData:function (event) { var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1​ console.log (this.data[randomNum].name + " " + this.data[randomNum].age); } } // Assign the showData method of the user object to a variable​ var showDataVar = user.showData; showDataVar (); // Samantha 12 (from the global data array, not from the local data array)​ /* This happens because showDataVar () is executed as a global function and use of this inside showDataVar () is bound to the global scope, which is the window object in browsers. */ // Bind the showData method to the user object​ var showDataVar = user.showData.bind (user); // Now the we get the value from the user object because the this keyword is bound to the user object​ showDataVar (); // P. Mickelson 43​ 
  • bind() nous permet d'emprunter des méthodes

     // Here we have a cars object that does not have a method to print its data to the console​ var cars = { data:[ {name:"Honda Accord", age:14}, {name:"Tesla Model S", age:2} ] } // We can borrow the showData () method from the user object we defined in the last example.​ // Here we bind the user.showData method to the cars object we just created.​ cars.showData = user.showData.bind (cars); cars.showData (); // Honda Accord 14​ 

    Un problème avec cet exemple est que nous ajoutons une nouvelle méthode showData sur l'objet des cars et que nous ne voulons pas le faire simplement pour emprunter une méthode parce que l'objet des voitures peut déjà avoir un nom de propriété ou de méthode showData . Nous ne voulons pas l'écraser accidentellement. Comme nous le verrons lors de notre discussion sur Apply and Call ci-dessous, il est préférable d'emprunter une méthode en utilisant la méthode Apply ou Call .

  • bind() nous permet de curry une fonction

    Fonction Currying , également appelée application de fonction partielle , est l'utilisation d'une fonction (qui accepte un ou plusieurs arguments) qui renvoie une nouvelle fonction avec certains des arguments déjà définis.

     function greet (gender, age, name) { // if a male, use Mr., else use Ms.​ var salutation = gender === "male" ? "Mr. " : "Ms. "; if (age > 25) { return "Hello, " + salutation + name + "."; }else { return "Hey, " + name + "."; } } 

    Nous pouvons utiliser bind() pour curry cette fonction de greet

     // So we are passing null because we are not using the "this" keyword in our greet function. var greetAnAdultMale = greet.bind (null, "male", 45); greetAnAdultMale ("John Hartlove"); // "Hello, Mr. John Hartlove." var greetAYoungster = greet.bind (null, "", 16); greetAYoungster ("Alex"); // "Hey, Alex."​ greetAYoungster ("Emma Waterloo"); // "Hey, Emma Waterloo." 
  • apply() ou call() pour définir cette valeur

    Les méthodes d' apply , d' call et de bind sont toutes utilisées pour définir la valeur actuelle lors de l'appel d'une méthode, et elles le font de manière légèrement différente pour permettre l'utilisation d'un contrôle direct et d'une polyvalence dans notre code JavaScript.

    Les méthodes d' apply et d' call sont presque identiques lors du réglage de la valeur de valeur, sauf que vous passez les paramètres de fonction à apply () tant que tableau , alors que vous devez lister les paramètres individuellement pour les transmettre à la méthode call () .

    Voici un exemple pour utiliser l' call ou apply pour définir ceci dans la fonction de rappel.

     // Define an object with some properties and a method​ // We will later pass the method as a callback function to another function​ var clientData = { id: 094545, fullName: "Not Set", // setUserName is a method on the clientData object​ setUserName: function (firstName, lastName) { // this refers to the fullName property in this object​ this.fullName = firstName + " " + lastName; } }; function getUserInput (firstName, lastName, callback, callbackObj) { // The use of the Apply method below will set the "this" value to callbackObj​ callback.apply (callbackObj, [firstName, lastName]); } // The clientData object will be used by the Apply method to set the "this" value​ getUserInput ("Barack", "Obama", clientData.setUserName, clientData); // the fullName property on the clientData was correctly set​ console.log (clientData.fullName); // Barack Obama 
  • Fonctions d'emprunt avec apply ou call

    • Méthodes de Borrow Array

      Créez un objet array-like un array-like et empruntez des méthodes de tableau pour fonctionner sur notre objet de tableau.

       // An array-like object: note the non-negative integers used as keys​ var anArrayLikeObj = {0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 }; // Make a quick copy and save the results in a real array: // First parameter sets the "this" value​ var newArray = Array.prototype.slice.call (anArrayLikeObj, 0); console.log (newArray); // ["Martin", 78, 67, Array[3]]​ // Search for "Martin" in the array-like object​ console.log (Array.prototype.indexOf.call (anArrayLikeObj, "Martin") === -1 ? false : true); // true​ 

      Un autre cas commun est que les arguments conversion en tableau comme suit

        // We do not define the function with any parameters, yet we can get all the arguments passed to it​ function doSomething () { var args = Array.prototype.slice.call (arguments); console.log (args); } doSomething ("Water", "Salt", "Glue"); // ["Water", "Salt", "Glue"] 
    • Emprunter d'autres méthodes

       var gameController = { scores :[20, 34, 55, 46, 77], avgScore:null, players :[ {name:"Tommy", playerID:987, age:23}, {name:"Pau", playerID:87, age:33} ] } var appController = { scores :[900, 845, 809, 950], avgScore:null, avg :function () { var sumOfScores = this.scores.reduce (function (prev, cur, index, array) { return prev + cur; }); this.avgScore = sumOfScores / this.scores.length; } } // Note that we are using the apply () method, so the 2nd argument has to be an array​ appController.avg.apply (gameController); console.log (gameController.avgScore); // 46.4​ // appController.avgScore is still null; it was not updated, only gameController.avgScore was updated​ console.log (appController.avgScore); // null​ 
  • Utilisez apply() pour exécuter la fonction variable-arity

Math.max est un exemple de fonction d' Math.max variable,

 // We can pass any number of arguments to the Math.max () method​ console.log (Math.max (23, 11, 34, 56)); // 56 

Mais que se passe-t-il si nous disposons d'un ensemble de nombres pour passer à Math.max ? Nous ne pouvons pas faire ceci:

 var allNumbers = [23, 11, 34, 56]; // We cannot pass an array of numbers to the the Math.max method like this​ console.log (Math.max (allNumbers)); // NaN 

C'est là que la méthode apply () nous aide à exécuter des fonctions variadiques . Au lieu de ce qui précède, nous devons passer le nombre de nombres en utilisant apply ( ) ainsi:

 var allNumbers = [23, 11, 34, 56]; // Using the apply () method, we can pass the array of numbers: console.log (Math.max.apply (null, allNumbers)); // 56 
  • L'appel invoque la fonction et vous permet de passer les arguments un par un.
  • Appliquer invoque la fonction et vous permet de passer des arguments en tant que tableau.
  • Lier renvoie une nouvelle fonction, vous permettant de passer dans ce tableau et un nombre quelconque d'arguments.

Appel / application exécute la fonction immédiatement:

 func.call(context, arguments); func.apply(context, [argument1,argument2,..]); 

Bind n'exécute pas la fonction immédiatement, mais renvoie la fonction d' application enveloppée (pour une exécution ultérieure):

 function bind(func, context) { return function() { return func.apply(context, arguments); }; } 

Appel appliqué et lié. Et comment ils sont différents.

Permet d'apprendre à appeler et de postuler en utilisant une terminologie quotidienne.

Vous avez trois automobiles your_scooter , your_car and your_jet qui commencent par le même mécanisme (méthode). Nous avons créé un objet automobile avec une méthode push_button_engineStart .

 var your_scooter, your_car, your_jet; var automobile = { push_button_engineStart: function (runtime){ console.log(this.name + "'s" + ' engine_started, buckle up for the ride for ' + runtime + " minutes"); } } 

Comprend quand l'appel et l'application sont utilisés. Supposons que vous êtes un ingénieur et que vous possédez your_scooter , your_car et your_jet qui ne sont pas accompagnés d'un push_button_engine_start et que vous souhaitez utiliser un tiers push_button_engineStart .

Si vous exécutez les lignes de code suivantes, elles vous donneront une erreur. POURQUOI?

 //your_scooter.push_button_engineStart(); //your_car.push_button_engineStart(); //your_jet.push_button_engineStart(); automobile.push_button_engineStart.apply(your_scooter,[20]); automobile.push_button_engineStart.call(your_jet,10); automobile.push_button_engineStart.call(your_car,40); 

Ainsi, l'exemple ci-dessus donne avec succès votre_scooter, votre_car, votre_jet une caractéristique de l'objet automobile.

Plongeons plus loin. Ici, nous diviserons la ligne de code ci-dessus. automobile.push_button_engineStart nous aide à obtenir la méthode utilisée.

En outre, nous utilisons appliquer ou appeler en utilisant la notation par points. automobile.push_button_engineStart.apply()

Maintenant appliquez et appelez acceptez deux paramètres.

  1. le contexte
  2. arguments

Donc, nous définissons ici le contexte dans la dernière ligne de code.

automobile.push_button_engineStart.apply(your_scooter,[20])

La différence entre l'appel et l'application est juste que s'applique accepte les paramètres sous la forme d'un tableau alors que l'appel peut simplement accepter une liste d'arguments séparée par des virgules.

Quelle est la fonction JS Bind?

Une fonction de liaison est essentiellement liée au contexte de quelque chose, puis la stocke en une variable pour l'exécution à un stade ultérieur.

Rendons notre exemple précédent encore mieux. Plus tôt, nous avons utilisé une méthode appartenant à l'objet automobile et l'avons utilisé pour équiper votre your_car, your_jet and your_scooter . Maintenant, imaginez que nous voulons donner un push_button_engineStart séparé séparément pour démarrer nos automobiles individuellement à toute étape ultérieure de l'exécution que nous souhaitons.

 var scooty_engineStart = automobile.push_button_engineStart.bind(your_scooter); var car_engineStart = automobile.push_button_engineStart.bind(your_car); var jet_engineStart = automobile.push_button_engineStart.bind(your_jet); setTimeout(scooty_engineStart,5000,30); setTimeout(car_engineStart,10000,40); setTimeout(jet_engineStart,15000,5); 

Toujours pas satisfait?

Allons le préciser en larmes. Temps d'expérimentation. Nous allons appeler et appliquer une application de fonction et essayer de stocker la valeur de la fonction comme référence.

L'expérience ci-dessous échoue parce que l'appel et l'application sont invoqués immédiatement; par conséquent, nous n'arrivons jamais à enregistrer une référence dans une variable où la fonction bind détruit le spectacle

var test_function = automobile.push_button_engineStart.apply(your_scooter);

 function printBye(message1, message2){ console.log(message1 + " " + this.name + " "+ message2); } var par01 = { name:"John" }; var msgArray = ["Bye", "Never come again..."]; printBye.call(par01, "Bye", "Never come again...");//Bye John Never come again... printBye.call(par01, msgArray);//Bye,Never come again... John undefined //so call() doesn't work with array and better with comma seperated parameters //printBye.apply(par01, "Bye", "Never come again...");//Error printBye.apply(par01, msgArray);//Bye John Never come again... var func1 = printBye.bind(par01, "Bye", "Never come again..."); func1();//Bye John Never come again... var func2 = printBye.bind(par01, msgArray); func2();//Bye,Never come again... John undefined //so bind() doesn't work with array and better with comma seperated parameters 

Imaginez, le lien n'est pas disponible. Vous pouvez facilement le construire comme suit:

 var someFunction=... var objToBind=.... var bindHelper = function (someFunction, objToBind) { return function() { someFunction.apply( objToBind, arguments ); }; } bindHelper(arguments); 

Je pense que les mêmes endroits sont: tous peuvent changer la valeur d'une fonction. Les différences sont les suivantes: la fonction de liage renverra une nouvelle fonction; Les méthodes d'appel et d'application exécuteront la fonction immédiatement, mais appliquer peut accepter un tableau comme paramètres, et il analysera le tableau séparé. Et aussi, la fonction de liaison peut être Currying.

La fonction bind doit être utilisée lorsque nous voulons affecter une fonction avec un contexte particulier, par exemple.

 var demo = { getValue : function(){ console.log('demo object get value function') } setValue : function(){ setTimeout(this.getValue.bind(this),1000) } } 

Dans l'exemple ci-dessus, si nous appelons la fonction demo.setValue () et passons cette fonction .getValue directement alors il n'appelle pas la fonction demo.setValue directement parce que ceci dans setTimeout fait référence à l'objet de fenêtre, donc nous devons transmettre le contexte d'objet de démonstration à this.getValue Fonction en utilisant bind. Cela signifie que nous ne faisons que fonctionner avec le contexte de l'objet de démonstration, pas une fonction appelante.

J'espère que tu comprends.

Pour plus d'informations, veuillez vous référer à la fonction javascript bind en détail