What is the difference between call and apply?

前端 未结 24 1659
太阳男子
太阳男子 2020-11-21 07:12

What is the difference between using call and apply to invoke a function?

var func = function() {
  alert(\'hello!\');
};


        
相关标签:
24条回答
  • 2020-11-21 07:50

    Another example with Call, Apply and Bind. The difference between Call and Apply is evident, but Bind works like this:

    1. Bind returns an instance of a function that can be executed
    2. First Parameter is 'this'
    3. Second parameter is a Comma separated list of arguments (like Call)

    }

    function Person(name) {
        this.name = name; 
    }
    Person.prototype.getName = function(a,b) { 
         return this.name + " " + a + " " + b; 
    }
    
    var reader = new Person('John Smith');
    
    reader.getName = function() {
       // Apply and Call executes the function and returns value
    
       // Also notice the different ways of extracting 'getName' prototype
       var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
       console.log("Apply: " + baseName);
    
       var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy"); 
       console.log("Call: " + baseName);
    
       // Bind returns function which can be invoked
       var baseName = Person.prototype.getName.bind(this, "is a", "boy"); 
       console.log("Bind: " + baseName());
    }
    
    reader.getName();
    /* Output
    Apply: John Smith is a boy
    Call: John Smith is a boy
    Bind: John Smith is a boy
    */
    
    0 讨论(0)
  • 2020-11-21 07:52

    The difference is that apply lets you invoke the function with arguments as an array; call requires the parameters be listed explicitly. A useful mnemonic is "A for array and C for comma."

    See MDN's documentation on apply and call.

    Pseudo syntax:

    theFunction.apply(valueForThis, arrayOfArgs)

    theFunction.call(valueForThis, arg1, arg2, ...)

    There is also, as of ES6, the possibility to spread the array for use with the call function, you can see the compatibilities here.

    Sample code:

    function theFunction(name, profession) {
        console.log("My name is " + name + " and I am a " + profession +".");
    }
    theFunction("John", "fireman");
    theFunction.apply(undefined, ["Susan", "school teacher"]);
    theFunction.call(undefined, "Claude", "mathematician");
    theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator

    0 讨论(0)
  • 2020-11-21 07:52

    Summary:

    Both call() and apply() are methods which are located on Function.prototype. Therefore they are available on every function object via the prototype chain. Both call() and apply() can execute a function with a specified value of the this.

    The main difference between call() and apply() is the way you have to pass in arguments into it. In both call() and apply() you pass as a first argument the object you want to be the value as this. The other arguments differ in the following way:

    • With call() you have to put in the arguments normally (starting from the second argument)
    • With apply() you have to pass in array of arguments.

    Example:

    let obj = {
      val1: 5,
      val2: 10
    }
    
    const summation = function (val3, val4) {
      return  this.val1 + this.val2 + val3 + val4;
    }
    
    console.log(summation.apply(obj, [2 ,3]));
    // first we assign we value of this in the first arg
    // with apply we have to pass in an array
    
    
    console.log(summation.call(obj, 2, 3));
    // with call we can pass in each arg individually

    Why would I need to use these functions?

    The this value can be tricky sometimes in javascript. The value of this determined when a function is executed not when a function is defined. If our function is dependend on a right this binding we can use call() and apply() to enforce this behaviour. For example:

    var name = 'unwantedGlobalName';
    
    const obj =  {
      name: 'Willem',
      sayName () { console.log(this.name);}
    }
    
    
    let copiedMethod = obj.sayName;
    // we store the function in the copiedmethod variable
    
    
    
    copiedMethod();
    // this is now window, unwantedGlobalName gets logged
    
    copiedMethod.call(obj);
    // we enforce this to be obj, Willem gets logged

    0 讨论(0)
  • 2020-11-21 07:54

    To answer the part about when to use each function, use apply if you don't know the number of arguments you will be passing, or if they are already in an array or array-like object (like the arguments object to forward your own arguments. Use call otherwise, since there's no need to wrap the arguments in an array.

    f.call(thisObject, a, b, c); // Fixed number of arguments
    
    f.apply(thisObject, arguments); // Forward this function's arguments
    
    var args = [];
    while (...) {
        args.push(some_value());
    }
    f.apply(thisObject, args); // Unknown number of arguments
    

    When I'm not passing any arguments (like your example), I prefer call since I'm calling the function. apply would imply you are applying the function to the (non-existent) arguments.

    There shouldn't be any performance differences, except maybe if you use apply and wrap the arguments in an array (e.g. f.apply(thisObject, [a, b, c]) instead of f.call(thisObject, a, b, c)). I haven't tested it, so there could be differences, but it would be very browser specific. It's likely that call is faster if you don't already have the arguments in an array and apply is faster if you do.

    0 讨论(0)
  • 2020-11-21 07:54

    Let me add a little detail to this.

    these two calls are almost equivalent:

    func.call(context, ...args); // pass an array as list with spread operator
    
    func.apply(context, args);   // is same as using apply
    

    There’s only a minor difference:

    • The spread operator ... allows passing iterable args as the list to call.
    • The apply accepts only array-like args.

    So, these calls complement each other. Where we expect an iterable, call works, where we expect an array-like, apply works.

    And for objects that are both iterable and array-like, like a real array, we technically could use any of them, but apply will probably be faster because most JavaScript engines internally optimize it better.

    0 讨论(0)
  • 2020-11-21 07:55

    I'd like to show an example, where the 'valueForThis' argument is used:

    Array.prototype.push = function(element) {
       /*
       Native code*, that uses 'this'       
       this.put(element);
       */
    }
    var array = [];
    array.push(1);
    array.push.apply(array,[2,3]);
    Array.prototype.push.apply(array,[4,5]);
    array.push.call(array,6,7);
    Array.prototype.push.call(array,8,9);
    //[1, 2, 3, 4, 5, 6, 7, 8, 9] 
    

    **details: http://es5.github.io/#x15.4.4.7*

    0 讨论(0)
提交回复
热议问题