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!
– LeAndrade