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

后端 未结 22 1947
醉话见心
醉话见心 2020-11-22 02:42

I already know that apply and call are similar functions which setthis (context of a function).

The difference is with the way

相关标签:
22条回答
  • 2020-11-22 03:34

    Assume we have multiplication function

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

    Lets create some standard functions using bind

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

    Now multiby2(b) is equal to multiplication(2,b);

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

    What if I pass both the parameters in bind

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

    Now getSixAlways() is equal to multiplication(3,2);

    getSixAlways();//6
    

    even passing parameter returns 6; getSixAlways(12); //6

    var magicMultiplication = multiplication.bind(this);
    

    This create a new multiplication function and assigns it to magicMultiplication.

    Oh no, we are hiding the multiplication functionality into magicMultiplication.

    calling magicMultiplication returns a blank function b()

    on execution it works fine magicMultiplication(6,5); //30

    How about call and apply?

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

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

    In simple words, bind creates the function, call and apply executes the function whereas apply expects the parameters in array

    0 讨论(0)
  • 2020-11-22 03:34

    Here is one good article to illustrate the difference among bind(), apply() and call(), summarize it as below.

    • bind() allows us to easily set which specific object will be bound to this when a function or method is invoked.

      // 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() allow us to borrow methods

      // 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​
      

      One problem with this example is that we are adding a new method showData on the cars object and we might not want to do that just to borrow a method because the cars object might already have a property or method name showData. We don’t want to overwrite it accidentally. As we will see in our discussion of Apply and Call below, it is best to borrow a method using either the Apply or Call method.

    • bind() allow us to curry a function

      Function Currying, also known as partial function application, is the use of a function (that accept one or more arguments) that returns a new function with some of the arguments already set.

      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 + ".";
          }
       }
      

      We can use bind() to curry this greet function

      // 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() or call() to set this value

      The apply, call, and bind methods are all used to set the this value when invoking a method, and they do it in slightly different ways to allow use direct control and versatility in our JavaScript code.

      The apply and call methods are almost identical when setting the this value except that you pass the function parameters to apply () as an array, while you have to list the parameters individually to pass them to the call () method.

      Here is one example to use call or apply to set this in the callback function.

      // 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
      
    • Borrow functions with apply or call

      • Borrow Array methods

        Let’s create an array-like object and borrow some array methods to operate on the our array-like object.

        // 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​
        

        Another common case is that convert arguments to array as following

          // 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"]
        
      • Borrow other methods

        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​
        
    • Use apply() to execute variable-arity function

    The Math.max is one example of variable-arity function,

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

    But what if we have an array of numbers to pass to Math.max? We cannot do this:

    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
    

    This is where the apply () method helps us execute variadic functions. Instead of the above, we have to pass the array of numbers using apply () thus:

    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
    
    0 讨论(0)
  • 2020-11-22 03:34

    Use bind for future calls to the function. Both apply and call invoke the function.

    bind() also allows for additional arguments to be perpended to the args array.

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

    0 讨论(0)
  • 2020-11-22 03:36

    I created this comparison between function objects, function calls, call/apply and bind a while ago:

    .bind allows you to set the this value now while allowing you to execute the function in the future, because it returns a new function object.

    0 讨论(0)
  • 2020-11-22 03:39

    Use .bind() when you want that function to later be called with a certain context, useful in events. Use .call() or .apply() when you want to invoke the function immediately, and modify the context.

    Call/apply call the function immediately, whereas bind returns a function that, when later executed, will have the correct context set for calling the original function. This way you can maintain context in async callbacks and events.

    I do this a lot:

    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.
    };
    

    I use it extensively in Node.js for async callbacks that I want to pass a member method for, but still want the context to be the instance that started the async action.

    A simple, naive implementation of bind would be like:

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

    There is more to it (like passing other args), but you can read more about it and see the real implementation on the MDN.

    Hope this helps.

    0 讨论(0)
  • 2020-11-22 03:39

    JavaScript Call()

    const person = {
        name: "Lokamn",
        dob: 12,
        print: function (value,value2) {
            console.log(this.dob+value+value2)
        }
    }
    const anotherPerson= {
         name: "Pappu",
         dob: 12,
    }
     person.print.call(anotherPerson,1,2)
    

    JavaScript apply()

        name: "Lokamn",
        dob: 12,
        print: function (value,value2) {
            console.log(this.dob+value+value2)
        }
    }
    const anotherPerson= {
         name: "Pappu",
         dob: 12,
    }
     person.print.apply(anotherPerson,[1,2])
    

    **call and apply function are difference call take separate argument but apply take array like:[1,2,3] **

    JavaScript bind()

        name: "Lokamn",
        dob: 12,
        anotherPerson: {
            name: "Pappu",
            dob: 12,
            print2: function () {
                console.log(this)
            }
        }
    }
    
    var bindFunction = person.anotherPerson.print2.bind(person)
     bindFunction()
    
    0 讨论(0)
提交回复
热议问题