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