web-dev-qa-db-fra.com

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

Je sais déjà que apply et call sont des fonctions similaires qui définissentthis (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

687
Royi Namir

Utilisez .bind() lorsque vous souhaitez que cette fonction soit appelée ultérieurement 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.

Call/apply appelle immédiatement la fonction, alors que bind renvoie une fonction qui, lorsqu'elle sera exécutée ultérieurement, aura le contexte correct défini pour appeler la fonction d'origine. De cette façon, vous pouvez conserver 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 abondamment dans Node.js pour les rappels asynchrones pour lesquels je souhaite transmettre une méthode de membre, mais je veux tout de même que le contexte soit l'instance qui a démarré l'action asynchrone.

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

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

Il y a plus que cela (comme passer d'autres arguments), mais vous pouvez en lire plus à ce sujet et voir la vraie mise en œuvre sur le MDN .

J'espère que cela t'aides.

725
Chad

Ils attachent tousthisà une fonction (ou à un objet) et la différence réside dans l'appel de la fonction (voir ci-dessous).

call attachesthisinto function et l'exécute 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 attachesthisdans la fonction et 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"

apply est similaire à call sauf qu'il prend un objet de type tableau au lieu de lister les arguments un par un:

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"                                     
403
CuriousSuperhero

Répondre en forme SIMPLEST

  • Call appelle la fonction et vous permet de transmettre des arguments un parone. 
  • Apply appelle la fonction et vous permet de passer des arguments sous forme de tableau. 
  • Bind renvoie une nouvelle fonction, vous permettant de passer un Ce tableau et un nombre quelconque d'arguments.

Exemples d'application, d'appel et de liaison

Appel

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}

say.call(person1, 'Hello'); // Hello Jon Kuperman
say.call(person2, 'Hello'); // Hello Kelly King

Appliquer

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}

say.apply(person1, ['Hello']); // Hello Jon Kuperman
say.apply(person2, ['Hello']); // Hello Kelly King

Lier

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say() {
    console.log('Hello ' + this.firstName + ' ' + this.lastName);
}

var sayHelloJon = say.bind(person1);
var sayHelloKelly = say.bind(person2);

sayHelloJon(); // Hello Jon Kuperman
sayHelloKelly(); // Hello Kelly King

Quand utiliser chacun

Appeler et appliquer sont assez interchangeables. Il suffit de décider s’il est plus facile d’envoyer un tableau ou une liste d’arguments séparés par des virgules.

Je me rappelle toujours lequel est lequel en se rappelant que Call est pour virgule (liste séparée) et Apply est pour Array.

Bind est un peu différent. Il retourne une nouvelle fonction. Call et Apply exécutent immédiatement la fonction en cours.

Bind est idéal pour beaucoup de choses. Nous pouvons l'utiliser pour curry des fonctions comme dans l'exemple ci-dessus. Nous pouvons prendre une simple fonction hello et la transformer en helloJon ou helloKelly. Nous pouvons également l’utiliser pour des événements comme onClick où nous ne savons pas quand ils seront licenciés, mais nous savons quel contexte nous voulons qu’ils aient.

Référence: codeplanet.io

112
Amit Shah

Il permet de définir la valeur pour this indépendamment 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 obtenir le même résultat avec call, cela ressemble à ceci:

  function sayHello(){
    alert(this.message);
  }

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

Les deux Function.prototype.call() et Function.prototype.apply() appellent une fonction avec une valeur this 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 this donnée et renvoie cette fonction sans l'exécuter.

Alors, 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

Cela devient vraiment intéressant lorsque vous ne liez pas seulement une valeur pour this, mais aussi pour son argument prop:

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

Nous pouvons maintenant faire ceci:

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

bind : Il lie la fonction avec la valeur fournie et le contexte mais n'exécute pas la fonction. Pour exécuter une fonction, vous devez l'appeler.

call : Il exécute la fonction avec le contexte et le paramètre fournis.

apply : Il exécute la fonction avec le contexte fourni et le paramètre en tant que tableau .

18
Siddhartha

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

  • bind() nous permet de définir facilement quel objet spécifique sera lié à this quand une fonction ou une méthode est appelé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 à l’objet cars et à Nous ne voudrions peut-être pas le faire uniquement pour emprunter une méthode car l’objet cars pourrait déjà avoir une propriété ou un nom de méthode showData.Nous ne voulons pas écraser accidentellement. Comme nous le verrons dans notre discussion de Apply et Call ci-dessous, Il est préférable d'emprunter une méthode à l'aide de la méthode Apply ou Call.

  • bind() nous permet de curry une fonction

    La 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 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 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 this value

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

    Les méthodes apply et call sont presque identiques lorsque vous définissez la valeur this sauf que vous transmettez les paramètres de la fonction à apply () sous la forme un tableau, tandis que vous devez répertorier les paramètres individuellement la méthode call ()

    Voici un exemple d'utilisation de call ou apply pour définir this 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 Emprunter un tableau

      Créons un objet array-like et empruntons des méthodes de tableau pour opérer sur notre objet semblable à un 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 courant est celui qui convertit arguments 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

Le Math.max est un exemple de fonction à arité 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 avons un tableau de nombres à transmettre à 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 ici que la méthode apply () nous aide à exécuter fonctions variadiques. Au lieu de ce qui précède, nous devons passer le tableau 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
17
zangw

appelle/applique 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 retourne la fonction apply enveloppée (pour une exécution ultérieure):

function bind(func, context) {
    return function() {
        return func.apply(context, arguments);
    };
}
8
Eldiyar Talantbek
  • Call appelle la fonction et vous permet de passer des arguments un par un. 
  • Apply appelle la fonction et vous permet de transmettre des arguments sous forme de tableau. 
  • Bind renvoie une nouvelle fonction, vous permettant de passer un tableau this et un nombre quelconque d'arguments.
5
Khalid Azam

La différence fondamentale entre Call, Apply et Bind est la suivante:

Lier sera utilisé si vous voulez que votre contexte d’exécution vienne plus tard dans l’image.

Ex:

var car = { 
  registrationNumber: "007",
  brand: "Mercedes",

  displayDetails: function(ownerName){
    console.log(ownerName + ' this is your car ' + '' + this.registrationNumber + " " + this.brand);
  }
}
car.displayDetails('Nishant'); // **Nishant this is your car 007 Mercedes**

Disons que je veux utiliser cette méthode dans une autre variable

var car1 = car.displayDetails('Nishant');
car1(); // undefined

Pour utiliser la référence de voiture dans une autre variable, vous devez utiliser

var car1 = car.displayDetails.bind(car, 'Nishant');
car1(); // Nishant this is your car 007 Mercedes

Parlons de l'utilisation plus étendue de la fonction bind

var func = function() {
 console.log(this)
}.bind(1);

func();
// Number: 1

Pourquoi? Parce que maintenant func est lié au numéro 1, si nous n'utilisons pas de lien dans ce cas, il pointe sur un objet global.

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

func();
// Object

Appelez, appliquez sont utilisés lorsque vous voulez exécuter l'instruction en même temps.

var Name = { 
    work: "SSE",
    age: "25"
}

function displayDetails(ownerName) {
    console.log(ownerName + ", this is your name: " + 'age' + this.age + " " + 'work' + this.work);
}
displayDetails.call(Name, 'Nishant')
// Nishant, this is your name: age25 workSSE

In apply we pass the array
displayDetails.call(Name, ['Nishant'])
// Nishant, this is your name: age25 workSSE
3
Nishant Parashar
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
2
Shiljo

J'ai créé cette comparaison entre les objets de fonction, les appels de fonction, call/apply et bind il y a quelque temps:

 enter image description here

.bind vous permet de définir la valeur thismaintenant tout en vous permettant d'exécuter la fonction à l'avenir, car elle renvoie un nouvel objet fonction.

2
Felix Kling

Call: call appelle la fonction et vous permet de passer des arguments un à un.

Apply: Apply appelle la fonction et vous permet de transmettre des arguments sous forme de tableau.

Bind: Bind renvoie une nouvelle fonction, vous permettant de passer un tableau this et un nombre quelconque d'arguments.

var person1 = {firstName: 'Raju', lastName: 'king'};
var person2 = {firstName: 'chandu', lastName: 'shekar'};

function greet(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}
function greet2(greeting) {
        console.log( 'Hello ' + this.firstName + ' ' + this.lastName);
    }


greet.call(person1, 'Hello'); // Hello Raju king
greet.call(person2, 'Hello'); // Hello chandu shekar



greet.apply(person1, ['Hello']); // Hello Raju king
greet.apply(person2, ['Hello']); // Hello chandu shekar

var greetRaju = greet2.bind(person1);
var greetChandu = greet2.bind(person2);

greetRaju(); // Hello Raju king
greetChandu(); // Hello chandu shekar

1
raju poloju

Imaginez, bind 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);
1
    function sayHello() {
            //alert(this.message);
            return this.message;
    }
    var obj = {
            message: "Hello"
    };

    function x(country) {
            var z = sayHello.bind(obj);
            setTimeout(y = function(w) {
//'this' reference not lost
                    return z() + ' ' + country + ' ' + w;
            }, 1000);
            return y;
    }
    var t = x('India')('World');
    document.getElementById("demo").innerHTML = t;
0
pandhari