jsgl.util.delegate
is a simple, yet powerful utility, which allows you to pair functions with objects on which the functions should be executed as methods.
Consider the following example:
function MyClass() { this.x = 10; } MyClass.prototype.foo = function() { alert(this.x); } var myInstance = new MyClass(); window.setTimeout(myInstance.foo, 1000); // will alert "undefined"
The above code will prompt undefined
, because, at the time of execution, the foo
function is not linked to the myInstance
object ā€“ it is simply an anonymous function, which substitutes this
with the global object at the time of execution. It is because the function has been passed as an argument.
In many situations, however, when passing function as an argument, you
might like to execute the function as a method of some given object.
This is when jsgl.util.delegate
becomes useful:
window.setTimeout(jsgl.util.delegate(myInstance, myInstance.foo), 1000); // prints "10"
The above code creates a new function, which actually executes the myInstance.foo
function as a method of myInstance
.
The above shown principle is very useful also when working with event handlers (not just in JSGL, but also in DHTML in general).
Again, consider a more complicated example:
function MyCircleWrapper(panel) { // constructor this.circle = panel.createCircle(); panel.addCircle(this.circle); this.circle.setRadius(30); with(this.circle.getStroke()) { setColor('blue'); setWeight(5); } this.circle.addMouseOverListener(this.mouseOver); // wrong! this.circle.addMouseOverListener(this.mouseOut); // wrong! } MyCircleWrapper.prototype.mouseOver = function() { // method this.circle.getStroke().setColor('red'); } MyCircleWrapper.prototype.mouseOut = function() { // method this.circle.getStroke().setColor('blue'); } MyCircleWrapper.prototype.moveCircle(x,y) { // method this.circle.setLocationXY(x,y); }
The above-example will throw unhandled exception
whenever the circle is moved over or out of the circle with the mouse
pointer. Again, it is because the functions registered as mouse
listeners do not have any connection to the proper MyCircleWrapper
instance.
Following the above example, you can fix the problem using jsgl.util.delegate
:
... this.circle.addMouseOverListener(jsgl.util.delegate(this, this.mouseOver)); this.circle.addMouseOutListener(jsgl.util.delegate(this, this.mouseOut)); ...