views:

79

answers:

3

In Javascript, if we are aliasing a function (or, assign a "reference to a function" to another variable), such as in:

f = g;
f = obj.display;
obj.f = foo;

all the 3 lines above, they will work as long as the function / method on the right hand side doesn't touch this? Since we are passing in all the arguments, the only way it can mess up is when the function / method on the right uses this?

Actually, line 1 is probably ok if g is also a property of window? If g is referencing obj.display, then the same problem is there.

In line 2, when obj.display touches this, it is to mean the obj, but when f is invoked, the this is window, so they are different.

In line 3, it is the same: when f is invoked inside of obj's code, then the this is obj, while foo might be using this to refer to window if it was a property of window. (global function).

So line 2 can be written as

f = function() { obj.display.apply(obj, arguments) }

and line 3:

obj.f = function() { foo.apply(window, arguments) }

Is this the correct method? And are there other methods besides this?

+1  A: 

The meaning of "this" and scopes as they apply to functions, especially callbacks, seems to be a classic JavaScript "gotcha".

Dojo has a hitch() method which addresses the problem, giving a nice way to get the expected context for callback methods. I guess a non-dojo developer could have a look at the Dojo hitch() code to borrow the ideas.

This article explains some aspects of the "this" problem and how to use Dojo hitch().

djna
+1  A: 

'this' will only refer to the right object inside your function if you invoke an object in this way:

obj.f();

This will never work, as javascript lacks support for "bound functions" (doesn't remember what object a method belongs to):

var x = context.lineTo;
x(10,10);

lineTo will get confused as 'this' now points to the window or current function object instead of its expected context. So indeed, you always need apply in your case.

wump
+3  A: 

Basically yes, however, in JavaScript functions are first class objects, so there it is not really aliasing. What you are doing is assigning the value of a variable to another variable, an in this case the value just happens to be a function.

The magic this variable however is a little bit different. In JavaScript methods are not bound to a class or an object, like they are in most other languages. When you call a method the this is set by the dot operator, or by the apply or call methods. It works like this:

var i = 1;
var f = function () { alert(this.i); }
f(); // in a browser, alerts 1, because this will be window if it isn't anything else.

var obj = { i: 10 };
obj.g = f;
obj.g(); // alerts 10, because the dot binds this to obj

var other_obj = { i: 23 };
f.apply(g); // alerts 23, because now apply binds this to other_obj

You can bind methods to objects by using closures:

var f = function () { alert(this.i); }
var obj = { i: 10 };

obj.m = function () { f.apply(obj); }
obj.m(); // alerts 10

var g = obj.m;
g(); // alerts 10, because now the closure is called, which binds this correctly.
AHM