Javascript OO: Scope of ‘this’ variable when using prototype.js
Mar.06, 2008 in
Development
If you write a fair bit of OO javascript and also utilise AJAX through one of the many frameworks (I personally use prototype.js most of the time) you may have come across the following issue:
var myobj = new Object();
myobj.Methods = {
result: 0,
callAjax: function() {
new Ajax.Request('ajax.php', {
onComplete: function(transport) {
this.result = transport.responseText.evalJSON();
}
}
}
};
Object.extend(myobj, myobj.Methods);
The problem with the above is that when you make the Ajax.Request() call and instigate a function call in the onComplete hook, this is no longer a reference to your original object. You have to change the line above to:
myobj.result = transport.responseText.evalJSON();
This way you are referencing the globally scoped myobj object and can make changes to its properties from within your anonymous function.
Tags: javascript, prototype.js

March 11th, 2008 at 6:57 am
Alternate solutions are to write something like:
callAjax: function() {
var me = this;
new Ajax.Request(‘ajax.php’, {
onComplete: function(transport) {
me.result = transport.responseText.evalJSON();
}
}
}
or
callAjax: function() {
new Ajax.Request(‘ajax.php’, {
onComplete: (function(transport) {
this.result = transport.responseText.evalJSON();
}).bind(this);
}
}
In the former case “me” is set to the callAjax’s containing object and since “me” is not “this” it’s unaffected by onComplete’s bindings. The latter uses Prototype’s bind() method to state that onComplete’s “this” refers to the same object as callAjax’s “this” (effectively by encapsulating the former idiom).
In either case, the advantage is that “myobj” isn’t explicitly mentioned, so it doesn’t need to be globally scoped, and the same method can be aggregated by other objects without them mistakenly messing with myobj’s result.
September 7th, 2008 at 6:01 am
Hayley Watson, you saved my day