Defining Classes in JavaScript

You, probably just like me prefer to organize your JavaScript code in the class structure. JavaScript does not provide class construct, nor it is necessary to organize your code in classes like C#. However, if you are coming from class-based, strongly typed object-oriented languages like C# or Java, it makes perfect sense to organize your client side code as well in classes. JavaScript code could quickly turn into big ball of spaghetti if you don’t structure it well. There are multiple ways to simulate or approximate the class like structure in JavaScript. In this post, I will cover

  • Constructor and Properties
  • Public Methods
  • Private Members
  • Static Members

As mentioned earlier, JavaScript doesn’t support class construct(it’s been proposed at part of ECMAScript 6). However, it has something called ‘constructor function’. The constructor function is just a regular function called with keyword new. Constructor function creates a new Object and sets this within that function to the newly created object. You could think of Object as the base class of all the objects in JavaScript just like in C#. Following code snippet outlines the basic class structure. Do not worry, if you don’t understand all the details at first, we are going to dissect it in a moment.

var Car;
Car = (function () {
    function Car(make, model) {
        this.make =  make;
        this.model =  model;
    }

    return Car;
}());

Let’s break apart this code as shown in the image below.

Constructor and Properties

Style of declaration in (A) is called ‘immediate function’, the immediate function is a function that is executed as soon as it is defined. Think of var Car as a variable that will be holding blueprint of your class. The function that is being assigned to it is wrapped in parenthesis, and the function itself has parenthesis at the end. The return value of this function will be assigned to variable Car. We could create an instance of Car by using the new keyword like new Car();.

Function indicated in (B) is the actual function that will be returned. When this function is called with keyword new, JavaScript will create instance of an Object(same as you might create using {} or new Object()) and sets this to the newly created object. Now, you could attach properties to this just by putting .. Line #4 and #5 defines property make and model and assigns the value passed in the arguments. You could pass and access arguments to constructor function same as any regular function. Line #8 returns this function. Now, you could create instance of car as

maybatch = new Car("Daimler AG", "Maybach Guard");
ferrari = new Car("Fiat", "Ferrari Laferrari");

console.log(maybatch.make);
console.log(ferrari.make);

At first, you might feel the syntax for classes confusing and terrible, but it would make more sense once you get used to it.

Public Methods

Now, let’s add start and stop methods to our Car class. You could add methods just like we added the model and make properties. However, doing so is very inefficient as JavaScript creates copy of the function for each instance of the object. Here is where the prototype comes into the picture.

var Car;
Car = (function () {
    function Car(make, model) {
        this.make =  make;
        this.model =  model;
    }

    Car.prototype.start = function () {
        console.log(' Started....' + this.model);
    };

    Car.prototype.stop = function () {
        console.log(' Stopped....' + this.model);
    };

    return Car;
}());

Every function in JavaScript has a property called prototype. prototype is of type Object, so you could attach methods and properties just like your regular object. All the methods and properties added to the prototype are available in all the objects created through constructor function. Other methods and properties of the object would be accessible using this keyword(well… in most cases, there is a gotcha and a workaround covered later in details).

Private Members

Variables defined within the constructor becomes the private members. However, the catch is that the private members are not accessible from outside the object nor from the public methods of the object. It would require a ‘privileged’ method, which could access private members. These ‘privileged’ methods can’t be part of the prototype, so the downside is that a separate instance of the function is created for each instance of the object. Duplicating the method per instance is inefficient. Also, it isn’t garbage collected. Because of these gotchas it is good to avoid private members unless you have a compelling reason to do so. Let’s add a private method called checkOilLife and a privileged method isServiceRequired. You will be able to access isServiceRequired but not the checkOilLife from outside the object.

var Car;
Car = (function () {
    function Car(make, model) {
        this.make =  make;
        this.model =  model;

        var checkOilLife = function () {
            return 80; //just hard code to 80%
        };

        this.isServiceRequired = function () {
            return checkOilLife() < 20; //service required if oil life is below 20%
        };
    }

    Car.prototype.start = function () {
        console.log(' Started....' + this.model);
    };

    Car.prototype.stop = function () {
        console.log(' Stopped....' + this.model);
    };

    return Car;
}());

Static Members

Adding static methods or properties are as easy as simply assigning it to the constructor function. Let’s add static property wheelCount and static method isValidVINFormat.

var Car;
Car = (function () {
    function Car(make, model) {
        this.make =  make;
        this.model =  model;

        var checkOilLife = function () {
            return 80; //just hard code to 80%
        };

        this.isServiceRequired = function () {
            return checkOilLife() < 20; //service required if oil life is below 20%
        };
    }

    Car.prototype.start = function () {
        console.log(' Started....' + this.model);
    };

    Car.prototype.stop = function () {
        console.log(' Stopped....' + this.model);
    };

    Car.wheelCount = 4;

    Car.isValidVIN = function (vin) {
        return vin !== null && vin.length === 17;
    };

    return Car;
}());

These two static members could be accessed as

Car.wheelCount;
Car.isValidVIN('4ffsdfdsfs');

All right, so now fire-up your favorite code editor and try out these concepts. There is no better way to really ‘get’ these concepts than really using it. In the next post, I will be covering other aspects of object-oriented programming in JavaScript. Subscribe to the mailing list and stay tuned.