Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Function.prototype.apply to set javascript callback scope

It's frustrating to have to manually set the scope of an object every time I declare a callback in JavaScript, but it's a fact of life. I wondered if I could do it by passing [mycallback].apply as the callback, and the scope object as an argument, like so:

var f = function() { console.log(this.x); };
var o = {x: 3};
setTimeout(f.apply, 1000, o);

As far as I can tell, this should call f with o as the scope, but instead Chrome gives me "Uncaught TypeError: Function.prototype.apply was called on [object DOMWindow], which is a object and not a function". Why doesn't this work?

like image 400
incidentist Avatar asked Mar 25 '11 00:03

incidentist


People also ask

How do you bind a callback function?

You can achieve this by calling bind(this) for your function: function myFunction() { console. log(this); } // bind(this) creates a new function where the value of 'this' is fixed var boundFunction = myFunction. bind(this); // It's also possible to replace the function by it's bound version myFunction = myFunction.

What is the difference between using call () and apply () to invoke a function with multiple arguments?

The Difference Between call() and apply() The difference is: The call() method takes arguments separately. The apply() method takes arguments as an array. The apply() method is very handy if you want to use an array instead of an argument list.

What does apply () do in JavaScript?

apply() The apply() method calls the specified function with a given this value, and arguments provided as an array (or an array-like object).

What is the use function prototype call method?

prototype. call() The call() method calls the function with a given this value and arguments provided individually.


2 Answers

For the same reason you need to "set the scope" in the first place. Only the apply function is sent to setTimeout, its association with function f is lost. Thus Javascript assigns the global object, window, to this, as it would in any other case.

It is interesting to note that apply, while being a native function, is not special or magical in some way, and behaves in a way consistent to user defined functions in the setting of the this variable.

like image 164
MooGoo Avatar answered Oct 24 '22 07:10

MooGoo


@MooGoo's answer is correct, but perhaps more explanation is needed.

When you call the function apply on f like this:

f.apply(ctx, args);

...then you're executing apply in the context of f.

But when you pass a reference to apply to a function, like this:

setTimeout(f.apply, 1000, o);

...that's all you're doing: passing a reference to the function f.apply. This is equivalent to passing Function.prototype.apply because:

console.log(f.apply === Function.prototype.apply); // true

Any connection to f is lost in window.setTimeout. It receives a reference to the generic apply function of Function.prototype. Nothing more. No context.

Therefore, as in any other case where an explicit context is not set, the apply function is called with window as its context object.

like image 31
Wayne Avatar answered Oct 24 '22 07:10

Wayne