igor
igor

Reputation: 2100

MooTools classes and `this` in delayed function calls

I have difficulties with using the this keyword in a MooTools (1.3) class. The constructor assigns a value to an attribute, and a subsequently run method displays this value in an alert popup. If I want to run this method delayed (using myfunction.delay(…)) the popup displays undefined.

var MyClass = new Class({   
    initialize: function() {
        this.x = 13;
    },               
    run: function() {
        alert(this.x);
    }
});
window.addEvent('domready', function() {
    var m = new MyClass();
    m.run();              // ``13''
    m.run.delay(2000);    // ``undefined''
});

After fiddling around, I managed to find the following solution:

window.addEvent('domready', function() {
    var m = new MyClass();
    (function() { m.run() }).delay(2000);    // ``13''
});

Still, I would like to understand what’s happening here, and why simply calling m.run.delay(…) doesn’t do the trick.

Upvotes: 1

Views: 693

Answers (2)

gblazex
gblazex

Reputation: 50109

When you invoke a function as m.run() the this keyword will refer to the base object m. Function.prototype.delay however probably uses setTimeout to invoke your delayed function.

Function.prototype.delay = function(ms) {
  setTimeout(this, ms);
}

The problem with this form is that setTimeout will invoke your function without the base object reference, so this will refer to the global object (~ window).

The solution is to pass the object of invocation to delay explicitly.

/**
 * delay - (number) The duration to wait (in milliseconds).
 * bind  - (object, optional) The object that the "this" of the function
 *          will refer to.
 * args  - (mixed, optional) The arguments passed (must be an array if the 
 *          arguments are greater than one).
 */
m.run.delay(2000, m); 

Upvotes: 0

Anurag
Anurag

Reputation: 141879

When we call delay on a function, that function will be executed in the context of the global object (usually window). The solution is to wrap it inside another function and capture the object m in the closure.

An easier way to doing this is to use the bind parameter in the call to delay. The bind parameter specifies what the this value should refer to inside the function when it is invoked.

m.run.delay(2000, m);

Upvotes: 4

Related Questions