Does anyone know of a way to get around declaring var self = this when using JavaScript in an OO fashion? I see it quite often and was curious if its just something you have to do, or if there really is a way (perhaps a class library?) that lets you get around it? I do realize why it is necessary (this has function scope). But you never know what clever ways may be out there..
For example, I usually code my "classes" like this in JS:
function MyClass() {
}
MyClass.prototype = {
firstFunction: function() {
var self = this;
$.ajax({
...
success: function() {
self.someFunctionCall();
}
});
},
secondFunction: function() {
var self = this;
window.setTimeout(function() {
self.someOtherFunction();
}, 1000);
}
};
Does anyone know of a way to get around declaring var self = this when using JavaScript in an OO fashion? I see it quite often and was curious if its just something you have to do, or if there really is a way (perhaps a class library?) that lets you get around it? I do realize why it is necessary (this has function scope). But you never know what clever ways may be out there..
For example, I usually code my "classes" like this in JS:
function MyClass() {
}
MyClass.prototype = {
firstFunction: function() {
var self = this;
$.ajax({
...
success: function() {
self.someFunctionCall();
}
});
},
secondFunction: function() {
var self = this;
window.setTimeout(function() {
self.someOtherFunction();
}, 1000);
}
};
constructor
property of the prototype
to point back to MyClass
since you set it to another object. Just append the following line to your code: MyClass.prototype.constructor = MyClass;
.
– Aadit M Shah
Commented
Jul 25, 2012 at 1:47
In your first function you can do this...
$.ajax({
context: this,
success: function() {
this.someFunctionCall();
}
});
In the second one, you can do this, though you'll need to shim .bind()
in older browsers...
window.setTimeout(function() {
this.someOtherFunction();
}.bind(this), 1000);
With jQuery, you could also do this...
window.setTimeout($.proxy(function() {
this.someOtherFunction();
}, this), 1000);
No, you need to do this if you want to refer to this
in a different context (such as a callback) since otherwise it will be reassigned to another object such as window
.
By the way, self
is a python convention - in JavaScript people generally use the convention that = this
. But it is just a matter of personal taste.
ES5 added the standard method called bind
which allows you to bind the this
of a function as well as the first n number of parameters. In the example above, you can avoid using self
by calling bind
.
$.ajax({
...
success: function() {
this.someFunctionCall();
}.bind(this);
});
For non-ES5 browsers you can use a shim for it such as the one found here: https://github./kriskowal/es5-shim
As an asside, I would avoid using self
in your coding pattern because self
is defined as a global variable that is equal to window
which is the global scope. In other words, if you accidentally forget to define self
you will silently get the global scope as the value instead of an exception. If you use that
instead, you will get an exception (unless someone above you defined it).
Some javascript frameworks have their own event handling mechanisms that allow you to set context for the handler function. This way, instead of using self = this
, you can simply specify this
as the context.
Other possibility that es to my mind is to pass the context in somewhere in global scope. Like
function MyClass() {
MyClass.instances.push(this);
}
MyClass.instances = new Array();
MyClass.getInstanceBySomeRelevantParameter = function(param) {
for (var i = 0; i < MyClass.instances.length; i++)
if (condition(param))
return MyClass.instances[i];
}
...
success: function(event) {
MyClass.getInstanceBySomeRelevantParameter(event).someFunctionCall();
}
You may always bind your methods to this
and then use it as follows:
function MyClass() {
}
MyClass.prototype = {
firstFunction: function() {
var funct = someFunctionCall.bind(this);
$.ajax({
...
success: function() {
funct();
}
});
},
secondFunction: function() {
var funct = someOtherFunction.bind(this);
window.setTimeout(function() {
funct();
}, 1000);
}
};
For properties just assign them to another variable.
I fooled around on JSFiddle, and came up with the below. It does assume that you are using a top level namespace. This makes it so you only need to declare self once (at the bottom). I wrapped the class in an anonymous function so self wouldn't have a global scope. The fiddle is: http://jsfiddle/bdicasa/yu4vs/
var App = {};
(function() {
App.MyClass = function() { }
App.MyClass.prototype = {
firstFunction: function() {
console.log('in first function');
console.log(self === this); // true
},
secondFunction: function() {
window.setTimeout(function() {
self.firstFunction();
console.log(self === this); // false
}, 100);
}
};
var self = App.MyClass.prototype;
})();
var myClass = new App.MyClass();
myClass.secondFunction();