Having developed code in C# and C++ for a number of years, I’ve recently begun to write web software using Javascript. Working out how classes and objects work has been a little confusing and it took a few hours for me to work out how to do things correctly.
In C# and C++ classes and objects work in a similar fashion – you define a class that contains member properties and methods and when you instantiate the class to create an object the methods in the class “belong” to the object, i.e. they can call other methods in the class knowing that the called methods will operate on the same instance members as the caller.
In Javascript, classes are achieved by exploiting the fact that everything is an object including functions. Essentially, in Javascript, a class is created by adding properties and methods to a function object. The following sections show examples of how to do things like define a class, construct an object, define properties and methods.
Simple Javascript Class with Constructor and Properties
Here is a simple Javascript class with a couple of property definitions:
function NumericTextBox(element) { // Record the allowable min and max. // this.Min = 0; this.Max = 1000000; }
The above example defines a NumericTextBox class that accepts an element object in its constructor. The class also defines a Min and a Max property and gives them default values. An object can then be instantiated and its properties set as follows:
var MyObj = new NumericTextBox($('#editfield')); MyObj.Min = 12; MyObj.Max = 15;
Note the use of the this keyword to define the properties inside the NumericTextBox constructor. The this points to the object being created by running the constructor, so executing this.Min defines a property Min in the object.
Adding methods to the Javascript Class
Adding a method to the class is done using the prototype keyword, e.g. to add a SetMin method to the NumericTextBox class, do:
NumericTextBox.prototype.SetMin = function (NewMin) { this.Min = NewMin; }
Note the use of the keyword this again (this.Min) when setting the value of a property on the object. this needs to be used to reference the object on which the SetMin method has been called. In languages like C# and C++ there would be no need to insert a this. reference but in Javascript there is.
Adding an Event Handler to the Element Passed to the Javascript Constructor
If we want to add an event handler to the element (JQuery object in this example) passed to the constructor of our class, we have to make sure that when the event is called it executes in the context of our object. For example:
function NumericTextBox(element) { this.Min = 0; this.Max = 1000000; var self = this; element.on('keyup', function (ev) { self.ReFormatText(ev.target); }) } NumericTextBox.prototype.ReFormatText = function (element) { }
Note that the keyup event handler calls the class member ReFormatText. However, when the event handler runs, it needs to call the ReFormatText method in the context of the correct object. Unfortunately, due to Javascript scoping rules, if we wrote:
this.ReFormatText(ev.target)
the this keyword would call the method in the wrong context. The method would be called in the context of the event handler function, not in the context of our example object. To get the method called in the correct context, we use the self variable instead, having set the value of self to the correct object context before we defined the event handler.
Calling other Methods in the Same Javascript Object
When one class method calls another in the same class, we need to use the this keyword again so that the called method runs in the correct context and references the correct object’s properties:
NumericTextBox.prototype.SetMin = function (NewMin) { this.Min = NewMin; this.EnsureMaxGreaterThanMin(); }
There are other ways of defining classes in Javascript but the above techniques allowed me to do everything I needed in a simple class I was developing. I was surprised at how different class definitions were in Javascript compared to C++ or C# but having worked out how to make sure the correct object context was being used in methods, I managed to do everything I needed.