Real difference between Call and Apply methods

Asked

Viewed 166 times

5

What is the difference between the methods call and apply? I could not identify the difference where one separates the arguments and the other generates a vector for the arguments:

function scope() {
        console.log(this, arguments.length);
    }
    scope() // window, 0
    scope.call("foobar", [ 1, 2 ]); // "foobar", 1
    scope.apply("foobar", [ 1, 2 ]); // "foobar", 2

2 answers

3

Unfortunately your example was not the best. I start by changing the example to show the arguments in full and not just your length:

function scope() {
    console.log(this, JSON.stringify(arguments));
}

scope.call("foobar", [ 1, 2 ]); // "foobar", 1
scope.apply("foobar", [ 1, 2 ]); // "foobar", 2

Pay attention to the difference between the two.

In the case of call the arguments sane:

{"0":[1,2]}

That is to say 1 argument that is an array [1,2], but in the apply we see:

{"0":1,"1":2}

Who are 2 arguments, the first is 1 and the second is 2.

That is to say in the call the array is all passed as a single parameter, but in the apply the array indicates the parameters to be passed as if you had written them manually.

So in your case do:

scope.apply("foobar", [1,2]);

Would be equivalent to doing:

foobar(1 , 2);

Expanding further into the same, do:

scope.apply("foobar", [1,2,3,4,5]);

Would correspond to:

foobar(1 , 2, 3, 4, 5);

So we see well that it is different to call the function with call.

Cenários Reais

Apply

It is useful when you have an array of elements to pass to a function, but this function does not expect an array but rather separate elements written directly.

One obvious case of this is the Math.max to calculate the maximum of several numbers:

const arr = [1, 2, 3 ,4, 5];

console.log(Math.max(arr));
console.log(Math.max.apply(null, arr));

Math.max(arr) doesn’t work because max does not support receiving an array directly. Math.max is waiting to receive the loose elements, like this:

Math.max(1, 2, 3, 4, 5)

Which is exactly what the apply does. Note also that I indicated null as the first parameter that is the parameter that will serve this in function, and in this case we don’t want any this.

Call

The call is common to be used in "heritage" in the old Javascript style without the reserved words class and super.

I’m going to take the example of MDN, which certainly may not be the best, but is still used in exactly this context. Imagine it has a function Produto to build products and then another to Comida in which Comida would be an extension of Produto.

The call to Produto within the builder of Comida would normally be done with call:

function Produto(nome, preco) {
  this.nome = nome;
  this.preco = preco;
}

function Comida(nome, preco) {
  Produto.call(this, nome, preco);
  this.categoria = 'comida';
}


let queijo = new Comida('feta', 5);
console.log(queijo);

Documentation:

  • Nice guy, very well explained!

2


The difference is in the parameter they use. While the apply will pass to the function an array, the call will pass individual values separated by comma:

Your example shows this:

scope.call("foobar", [ 1, 2 ]);
                     --------
                         ↑
                apenas 1 parâmetro
               arguments.length = 1


scope.apply("foobar", [ 1, 2 ]);
                      --------
                          ↑
                1 array com 2 itens
               arguments.length = 2

Another example of call:

scope.call("foobar", [ 1, 2 ], 3);
                     --------  -
                         ↑     ↑
                      2 parâmetros
                   arguments.length = 2

The apply does not generate a vector, it sends a vector as the second parameter to the function. Example:

function scope() {
   for(var item of arguments){
      console.log(item);
   }
}
scope.apply("foobar", ['abc','def','ghi']);

MDN documentation on apply:

Note: While the syntax of this Function is Almost identical to that of call(), the fundamental Difference is that call() accepts an argument list, while apply() accepts the single array of Arguments.

Free translation:

Note: Although the syntax of this function is almost the same as the call(), the fundamental difference is that call() accepts a list of arguments, whereas apply() accepted a simple array with arguments.

The same example above using call:

function scope() {
   for(var item of arguments){
      console.log(item);
   }
}
scope.call("foobar", ['abc','def','ghi']);

Note that the argument ['abc','def','ghi'] arrives at the function with an entire array. Unlike apply, that sends each vector item as a separate argument.

  • 1

    Got it, but, why then use call if it will not return the array correctly? Why does it exist?

  • It can send an array, it can send other arguments than array etc... it will treat each argument separately... with apply you can only send array... in the last example, see that it sends the normal array, but does not directly read the array items as it does apply. For example: scope.call("foobar", 1,2,3); is equal to scope.apply("foobar", [1,2,3]);... Then it will depend on your application, you can use one thing or another... you want to send an array to treat function, use apply... want to send arguments separately, use call.

  • 1

    All right, I got it man. Thank you!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.