loading gif

Object-oriented programming with JavaScript

Author: Gokan EKINCI
First publication date: 2015-12-12
License: CC BY-NC-SA

When you're programming in JavaScript one question you may ask to yourself may be : "Is JavaScript object-oriented ?" :
The answer is yes, there are two ways to do it: with prototypes or with classes (but since ECMAScript 6 specification only for classes). ES6 has been approved and published on June 17, 2015. But what was there before with ES5 ?
There was (and there will always be) prototype-based programming.

In this mini-tutorial, I am going to detail how to write structures with the function keyword and create objects with JavaScript ES5 (prototype-based programming), in the second part we will see the prototype inheritance with ES5, then I will show you what it is possible to do with ES6 (object-oriented programming with classes), finally we will see anonymous structures in a fourth part and visibility and static elements in a fifth part.

1. Creating structures and instantiating objects with JavaScript ES5 (prototype-based programming)

So let's create our first structure:

// Creating a structure
function Foo(arg1){
    /* *** ATTRIBUTES *** */
    this.attr1 = "One";
    this.attr2 = arg1;

    this.method1 = function(param1){
        console.log(this.attr1 + " " + this.attr2 + " " + param1);
    };
}

// Object instantiation
var myInstance = new Foo("Two");

// Using a method
myInstance.method1("Three");

So what can we say about this example of code ?

  1. In some languages the class keyword is used to create... classes ! But not in JavaScript ES5. Here we have created a "constructor function".
  2. Then we have used the this keyword... In fact we have used this keyword for declaring our attributes inside the constructor like in the Python language.
  3. The this keyword is also used for calling attributes inside member functions (or "methods" if you prefer this term).
  4. All the elements declared with the this keyword have public visibility by default.

You haven't noticed it yet maybe but something is wrong in this code... we have declared our method inside the structure (this method is also called a privileged method), so everytime your going to instantiate an object a new copy of the method1() function will be created and it will increase the memory usage of your client's browser !
So let's see how prototype-based programming is powerful :

// Creating a structure
function Foo(arg1){
    /* *** ATTRIBUTES *** */
    this.attr1 = "One";
    this.attr2 = arg1;

    /* *** DO NOT DECLARE YOUR METHODS HERE !!! *** */
}

/* *** DEFINING METHODS *** */
Foo.prototype.method1 = function(param1){
    console.log(this.attr1 + " " + this.attr2 + " " + param1);
};

// Object instantiation
var myInstance = new Foo("Two");

// Using a method
myInstance.method1("Three");

2. Inheritance with JavaScript ES5 (inheritance by prototype)

So we are going to create a new structure based on Foo:

// Creating a child structure
function ChildFoo(arg1, arg2){
    Foo.call(this, arg1); // Calling parent's constructor function
    this.attr3 = arg2;
}

/* *** INHERITANCE BY PROTOTYPE *** */
ChildFoo.prototype = Object.create(Foo.prototype);

/* *** DEFINING CHILD STRUCTURE'S METHODS *** */
ChildFoo.prototype.method2 = function(param1, param2){
    console.log(this.attr1 + " " + this.attr2 + " " + this.attr3 + " " + param1 + " " + param2);
};

// Object instantiation
var c = new ChildFoo("Two", "Three");

// Using a method
c.method1("Three");         // Inherited from Foo
c.method2("Four", "Five");

So what can we say about this example of code ?

  1. We are calling parent constructor with the call() function. This is similar to super in Java or base in C#. The first parameter must be this.
  2. We are doing an inheritance by prototype with Object.create(prototype). According to MDN, for Internet Explorer, Object.create() is only available since IE9. If you want to avoid this problem with old browsers, there's an alternative solution: replace ChildFoo.prototype = Object.create(Foo.prototype); by ChildFoo.prototype = new Foo(null); (this has a drawback: content of your parent constructor function will be called).

3. Object-oriented programming with JavaScript ES6

ES6 comes with a new programming style with "classes", a more familiar syntax for some developpers, but its only a syntaxic sugar for prototypes.
Note: The following ES6 examples may not work if your browser does not support ES6 but you can test with a transpiler like Babel.

Prototype-based programming (ES5/ES6) Object-oriented programming with classes (ES6 only)
function Foo(arg1){

    /* *** ATTRIBUTES *** */
    this.attr1 = "One";
    this.attr2 = arg1;

    /* *** DO NOT DECLARE YOUR METHODS HERE !!! *** */
}

/* *** DEFINING METHODS *** */
Foo.prototype.method1 = function(param1){
    console.log(this.attr1 + " " + this.attr2 + " " + param1);
};
class Foo {
    constructor(arg1){
        /* *** ATTRIBUTES *** */
        this.attr1 = "One";
        this.attr2 = arg1;


    }

    /* *** DEFINING METHODS *** */
    method1(param1){
        console.log(this.attr1 + " " + this.attr2 + " " + param1);
    }
}

Inheritance:

Prototype-based programming (ES5/ES6) Object-oriented programming with classes (ES6 only)
function ChildFoo(arg1, arg2){

    Foo.call(this, arg1); // Calling parent's constructor
    this.attr3 = arg2;

}

/* *** INHERITANCE BY PROTOTYPE *** */
ChildFoo.prototype = Object.create(Foo.prototype);
class ChildFoo extends Foo {
    constructor(arg1, arg2){
        super(arg1); // Calling parent's constructor function
        this.attr3 = arg2;
    }
}

4. Anonymous structure instance

With JavaScript, creating instances from anonymous structures is not very useful because of anonymous functions, but still, if you want to know how to use them...

literal object style (ES5/ES6) `new function` style (ES5/ES6) anonymous class style (ES6 only)
var anonymousInstance = {

    a:1, 
    b:2,
    c:function(){
        // Code...
    }

};

anonymousInstance.c();
var anonymousInstance = new function(){

    this.a = 1;
    this.b = 2;
    this.c = function(){
        // Code...
    };

};

anonymousInstance.c();
var anonymousInstance = new class {
    constructor(){
        this.a = 1;
        this.b = 2;
        this.c = function(){
            // Code...
        };
    }
};

anonymousInstance.c();

So what can we say about this example of code ?

  1. We have used three different syntaxes, but the purpose is the same.
  2. We have defined our functions inside the structure, without using prototypes, because usually an anonymous structure requires to be instantiated only 1 time.

It is still possible to use prototypes to define methods:

`Object.getPrototypeOf` syntax (requires IE9 or superior) `__proto__` syntax (requires ES6 compatible browser)
Object.getPrototypeOf(anonymousInstance).method2 = function(){
    console.log("method2 !!!");
};
anonymousInstance.__proto__.method2 = function(){
    console.log("method2 !!!");
};

5. Visibility and static elements

In this part, we are going to see how to create private attributes, privileged methods (you already saw it in the first part), and static elements.
It's "cool" to know those things, but keep in mind that a JavaScript developer doesn't really need those concepts, he/she will rather use public attributes and prototype declared methods.

function Bar(arg1, arg2){

    // PRIVATE ATTRIBUTE
    var privateAttribute = arg1;

    // PUBLIC ATTRIBUTE
    this.publicAttribute = arg2;

    // PRIVILEGED METHOD
    this.privilegedMethod = function(){
        return privateAttribute + this.publicAttribute;
    }
}

// PUBLIC STATIC ATTRIBUTE 
Bar.staticAttribute = "Static attribute !";

// PUBLIC STATIC METHOD
Bar.staticMethod = function(){
    return "Static method !";
};

var o = new Bar(2, 4);
console.log(o.privilegedMethod());
console.log(o.publicAttribute);
console.log(Bar.staticAttribute);
console.log(Bar.staticMethod());

So what can we say about this example of code ?

  1. We have just used the var keyword in order to declare our private attribute.
  2. A privileged method is a public method declared inside the constructor function, it may contain private and public elements.
  3. We don't use the prototype keyword for declaring static elements. As in the in other languages, a static method cannot contain elements from an instance.