I come across this code in jsGarden, and I cannot figure the meaning to chain call
and apply
together. Both will execute the function with a given context object, why it could be chained?
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
// Create an unbound version of "method"
// It takes the parameters: this, arg1, arg2...argN
Foo.method = function() {
// Result: Foo.prototype.method.call(this, arg1, arg2... argN)
Function.call.apply(Foo.prototype.method, arguments);
};
It's making a call to call
via apply
; that is, it's using call
to call a function ("method"), and it's using apply
to make the call because it's got the arguments in the form of an (almost) array.
So to take it apart:
Function.call
That's a reference to the call()
function available on all Function instances, inherited from the Function prototype.
Function.call.apply
That's a reference, via the reference to the call
function, to apply
. Because apply
is referenced via the call
object, when the call to apply
is made the this
value will be a reference to the call
function.
Function.call.apply(Foo.prototype.method, arguments);
So we're invoking the call
function via apply
, and passing Foo.prototype.method
to be the this
value, and the arguments to "Foo.mmethod" as the arguments.
I think it's basically the same effect as this:
Foo.method = function() {
var obj = arguments[0], args = [].slice.call(arguments, 1);
Foo.prototype.method.apply(obj, args);
}
but I'll have to try it to make sure. edit Yes that seems to be it. So I can summarize the point of that trick as being a way to invoke apply()
when the desired this
value is the first element of the array holding the parameters. In other words, usually when you call apply()
you've got the desired this
object reference, and you've got the parameters (in an array). Here, however, since the idea is that you pass in the desired this
as a parameter, then it needs to be separated out in order for a call to apply
to be made. Personally I would do it as in my "translation" because it's a little less mind-bending (to me), but I suppose one could get used to it. Not a common situation, in my experience.
I think the code should be like this:
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
Foo.method = function() {
//Notice this line:
Function.apply.call(Foo.prototype.method, this, arguments);
};
then
Foo.method(1,2,3) => function Foo() {} 1 2 3
Other examples:
Function.apply.call(Array,this,[1,2]) => [1, 2]
Function.call.apply(Array,this,[1,2]) => [window]
Function.call.call(Array,this,[1,2]) => [[1, 2]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With