Object Oriented Javascript

If you are reading this I’d like to assume you know what Javascript is and the fact that it’s object oriented, what not many people know though is how to do the most common object oriented “things” in Javascript, such as inheritance, private functions and such.

The fact that Javascript is prototype based and not class based is what makes it hard to get into for most programmers. If you come from Java, PHP, C#, C++, Python, Ruby or pretty much any language you’ll find objects in Javascript are a bit unique, and they certainly are but in a good way!

Prototypes

Let’s talk a little bit about prototypes first. What are prototypes? The concept is really simple in fact, whenever you ask an attribute to an object, it will look for that attribute in itself, and if it cannot find it, it will look for it in a special hidden attribute called prototype (which is also just an object), if it’s there it will return it, if not it will just return undefined.

There is a catch though, you can access the prototype attribute of functions! So you cannot do {}.prototype but you can do Object.prototype! That’s because Object is actually a function, we’ll talk more about that in the following sections.

Constructor Functions

As you might know a constructor is a function which gets called every time a new object is created, it’s used to initialize the new object.

Because Javascript has no classes the new keyword works on functions not classes, inside this function you can use the this keyword and it will point to your new object, for example:

function Person(name) { 
    this.name = name; 
}

We can now create a person

var person = new Person("Thomas O'Malley");
console.log(person.name); // logs "Thomas O'Malley"

The function Person is called a constructor function and it starts with a capital letter. It’s super important to start all your constructor functions with a capital letter, not only it’s a convention, but if you call that function without the new keyword you’ll get unexpected results! Inside the constructor function this now points to the Window global object, and doesn’t return anything unless you say so. This is one of the most criticized features of Javascript, the inconsistency of the this keyword.

If you start all your constructor functions with a capital letter you’ll know just by looking that it must be used with new. Another option is to avoid the usage of the new keyword whenever possible:

function person(name) {
    return {
        name: name
    };
}

This function also returns a new object. Which way to program is up to you, normally constructor functions is the only use case when using new is good, Douglas Crockford talks a bit about this in this YUI blog post.

A little more about the new keyword

Feel free to skip this little section, but I’d like to talk a bit about this keyword.

The new keyword creates a new empty object with our constructor function in the hidden prototype attribute, it then executes our function and binds this to the newly created object, finally it returns that object or if there’s a return statement, the value of that statement. MDN explains these steps nicely as follows

  1. A new object is created, inheriting from foo.prototype.
  2. The constructor function foo is called with the specified arguments and this bound to the newly created object. new foo is equivalent to new foo(), i.e. if no argument list is specified, foo is called without arguments.
  3. The object returned by the constructor function becomes the result of the whole new expression. If the constructor function doesn’t explicitly return an object, the object created in step 1 is used instead. (Normally constructors don’t return a value, but they can choose to do so if they want to override the normal object creation process.)

If you are interested you should check out the full article on MDN.

Encapsulation

One of the things that object oriented code allows you to do is hide certain functionality from the consumer, meaning you are able to keep an internal state for your object which is not needed for the consumer to know, this is sometimes referred as “black box” or Encapsulation.

Encapsulation is good, and it’s easy to implement in Javascript! Let’s see how

function Person(name) {
    var _name = name;
    return {
        name: function (name) {
            if(!name) {
                return _name;
            }

            _name = name;
        }
    };
}

Here we have a constructor function which returns an object, so that’s what the new keyword will return. That object uses a variable from inside the constructor function’s scope, which cannot be accessed from outside our new object!

function Person(name) {
    // our code from before...
}

var person = new Person('Mike');
console.log(person.name()); // "Mike"
person.name('John');
console.log(person.name()); // "John"
console.log(person._name); // undefined
console.log(_name); // undefined

What we just did is called a closure and they are used quite a lot in Javascript, it might seem hard to understand and use but it’s really handy once you get used to them!

Inheritance

One of object oriented programming most important concepts is inheritance, meaning an object an inherit all the properties and methods from another parent object, and then add specific functionality on their own.

It’s a bit tricky but we can do it in Javascript with no major hassle, the idea is to use the prototype attribute to hold our base (a.k.a parent) object, so we can easily override / overload them if needed.

function Weapon(name) {
    this.name = name;
}

function Sword() {
    this.damage = 12;

    this.attack = function () {
        return 'Attack with ' + this.name;
    };
}
Sword.prototype = new Weapon('Sword');

var sword = new Sword();
console.log(sword.name); // 'Sword'
console.log(sword.damage); // 12
console.log(sword.attack()); // Attack with Sword

Because we can access the prototype attribute when working with functions we simply create a constructor function and then add an object to it’s prototype.

Another alternative would be just copying the attributes from the parent object to the child if the child doesn’t already have them, personally I find the first solution more elegant, but sometimes the latter is just a better fit, a good use case is when working with objects instead of constructor functions. See for example jQuery’s extend.

A note on prototypes

When we use new to create a new object it copies the prototype onto the new object, meaning primitive values get copied by value, but objects are copied by reference, so for function definitions we should always write Constructor.prototype.myFunction. Here’s a simple demonstration of this concept

function a () { this.f = function () {} }
a.prototype.F = function () {}

var o1 = new a();
var o2 = new a();
o1.f === o2.f // false
o1.F === o2.F // true

Static vs Instance

In the example above, for each Sword object we created the prototype Weapon object was copied, meaning each sword had it’s own copy of Weapon; There’s one copy per instance.

Sometimes you want to make a static attribute, meaning it’s shared across all instances, this is useful for sharing methods and data instead of copying them over and over. To create static attributes we use the constructor function.

The new keyword only copies the prototype of the constructor function, if we add any regular property it won’t be there in the new object, but we can easily access it later on, as we see here

function Counter(name) {
    this.add = function () {
        console.log(++Counter.counter);
    };
}
Counter.counter = 0;

var counter = new Counter();
counter.add(); // 1
counter.add(); // 2
counter.add(); // 3

var counter2 = new Counter();
counter2.add(); // 4

Abstracting it up a bit

A lot of libraries already provide a bunch of helper methods to easily get away with this, abstracting quite a lot of complexity, for example, in CanJS you create a model constructor function as follows

var MyModel = can.Model.extend({ 
    /* static props */ 
}, 
{ 
    /* instance props */ 
});
var myModel = new MyModel();

Most libraries create an extend function in their objects which simplifies the inheritance process, this method normally either uses the prototype attribute or just overrides an object properties. For instance, take a look at this MDN article on Object.create and John Resig’s Simple Javascript Inheritance article.

There are a lot of abstractions, but knowing how to do them “by hand” is quite important to fully understand your code! There is no knowledge that is not power ;)

Conclusion

All in all OOP in Javascript is possible and not that hard to archieve, it surely is different though!

What I love about Javascript is that it’s such a simple language, you can do OOP as well as functional programming, or even mix both! In Javascript, that’s up to you.

I hope you find it useful and I’d like to hear your suggestions!

Cheers!

 
379
Kudos
 
379
Kudos

Now read this

Using Vim for web development

With all the fuss on Atom and Sublime Text, I decided to talk a bit about my favourite editor, Vim. I’ve tried both Sublime and Atom, I’ve especially used Sublime for quite some time before comitting to Vim, but ever since I’ve... Continue →