Object Oriented Programming In JavaScript – Part 1: The Basics

The Basics of Objects

In programming, objects are units of code which contain both data and functions which act on that data, all related to a specific entity within the system. They are used to model the semantics of the system. For example a customer relationship manager tool may contain Company objects and Contact objects. A Company object would represent a single company on the system, and a Contact a person within that company. Each Company would ‘own’ multiple Contact objects, as a Contact belongs to a Company. The objects would look something like this:

Company

  • id: int
  • name: string
  • address: string
  • contacts: array of Contact
  • addContact: function
  • removeContact: function

Contact

  • id: string
  • name: string
  • telephone: string
  • companyId: int

Traditional (Classical) Object Oriented Programming

In most Object Oriented programming languages, a class based system is used to implement objects. JavaScript is an exception to this norm. I want to show you how a more traditional (or classical) OO language implements objects by showing how the above Client and Contact objects would be implemented. This is a good starting point for learning JavaScript’s version of OO, as many people may be coming to JavaScript from a classical OO language. This way I will be able to point out the differences. If you’ve never used a classical OO language, you may want to skip this section.

The following is a PHP implementation. I’ve tried to get it right, but haven’t written PHP in years, so allow me to make some minor mistakes!

<?php
class Company {
    
    private $id; 
    private $name;
    private $address;
    private $contacts = []; 
    public function __construct($id, $name, $address) {
        $this->id = $id;
        $this->name = $name;
        $this->address = $address;
    }

    public function getContacts () {
        return $this->contacts;
    }

    public function addContact($contact) {
        array_push($this->contacts, $contact);
    }

    public function getId() {
        return $this->id;
    }

    public function getName() {
        return $this->name;
    }

    public function getAddress() {
        return $this->address;
    }
        
}

class Contact {

    private $id;
    private $name;
    private $telephone;
    private $companyId;

    public function __construct($id, $name, $telephone, $companyId) {
        $this->id = $id;
        $this->name = $name;
        $this->telephone = $telephone;
        $this->companyId = $companyId;
    }

    public function getId() {
        return $this->id;
    }

    public function getName() {
        return $this->name;
    }

    public function getTelephone() {
        return $this->telephone;
    }

    public function getCompanyId() {
        return $this->companyId;
    }
}

// Use the classes

// Create an instance of the class Company and store in $company
$company = new Company(1, 'MyCorp', '1 New Road');

// Create two separate instances of the Contact class, and store each in a variable
$contact1 = new Contact(1, 'John Smith', '01223 787876');
$contact2 = new Contact(1, 'Fred Brown', '01223 787877');
$company->addContact($contact1);
$company->addContact($contact2);

Here we have classes to represent both companies and contacts. Classes are blueprints for objects. Later on we use the ‘new’ keyword to create specific instances of objects. In much the same way as the blueprint for an iPhone isn’t an actual working iPhone, just the ‘design’ of how an iPhone should be once constructed, so it is that classes are not actual objects, but the design of how an object should be when constructed. This design contains all of the properties (data) and functions that objects of that class will have.

Designing software this way has many advantages, such as code reuse, but the pros and cons of Object Oriented Programming are beyond the scope of this post.

Objects in JavaScript

So now I’ve introduced the concept of classes and objects, and how they relate to one another, I’m going to kick your legs out from under you by telling you that JavaScript does not have classes*.

JavaScript just has objects and functions, and it uses objects and functions to create something that serves the same purpose as a class.

Prototypes and Functions as Objects

In chrome, paste the following code into the JavaScript console:

function foo () {}
foo.prototype;

The second line will evaluate to an object. There are two things you need to notice here. Firstly, any function in JavaScript, in this case foo, is also an object. This is evidenced by the fact it has a property on it (prototype), and only objects can have properties. Secondly, functions upon creation automatically have a property called ‘prototype’ which we can see when that second line gets evaluated. JavaScript is a prototypal rather than class based language, which means that this prototype object is key in creating blueprints from which object instances can be created.

Let’s implement the Company and Contact example in JavaScript so you can see this in action.

// Create constructor functions

function Company (id, name, address) {
    this.id = id;
    this.name = name;
    this.address = address;
    this.contacts = [];
}

// Add a member function to the prototype
Company.prototype.addContact = function (contact) {
    this.contacts.push(contact);
}

function Contact (id, name, telephone, companyId) {
        this.id = id;
        this.name = name;
        this.telephone = telephone;
        this.companyId = companyId;
}

// Use constructor functions to create object instances
company = new Company(1, 'MyCorp', '1 New Road');

contact1 = new Contact(1, 'John Smith', '01223 787876');
contact2 = new Contact(1, 'Fred Brown', '01223 787877');
company.addContact(contact1);
company.addContact(contact2);

First off, we create our constructor function, Company. A constructor function is not any different to a normal function, we just call it a constructor function because we are intending to use it to construct objects. Convention states that the name of constructor functions should begin with an upper case letter, but this is not enforced by the language.

The ‘this’ variable is very important in OO programming. It exists in JavaScript and many other languages. It allows the current instance of the object to reference itself. So within a function belonging to an object, ‘this’ refers to the current object.

The Company function assigns a number of properties to the ‘this’ object.

Next we assign a function that adds contacts to ‘this’, and this function is assigned to the addContact property of Company’s prototype object. Later we call the Company function with the ‘new’ keyword. This keyword tells JavaScript that we wish to use this function call as a constructor function, and that we want a new object instance returned as a result. This means that when we do this:

var company = new Company(1, ‘MyCorp’, ‘1 New Road’);

We get a new object stored in the company variable. For this object, the following will hold true:

  • company.id === 1
  • company.name === ‘MyCorp’
  • company.address === ‘1 New Road’
  • company.contacts is an empty array
  • company.addContact is a function

In other words, the constructor function has created us a new object and also populated it with our data. This is fairly easy to understand, but to get a really in depth knowledge of what’s going on I’m going to talk you through exactly what JavaScript does when we use the ‘new’ keyword. To understand this, I’ll first need to tell you all about internal prototypes.

Internal Prototypes

Whereas functions have an external prototype property we can access, all objects have a hidden, or internal, prototype property. This property is an object that contains all the properties that the object inherits from its constructor. You are not able to access or modify the internal prototype. Having said that, chrome does allow you to view this object in the console. Chrome calls this ‘__proto__’. You can see this property on a company object created by the demo code in the screenshot below.

Before we continue it is important to note that __proto__ is just something chrome adds to the console to aid debugging as JavaScript does not allow us to access the hidden internal prototype of an object. __proto__ probably won’t work in other browsers, and cannot be used in your code. Edit: __proto__ is now an official supported part of the JavaScript language.

We can see this object has 3 properties:

  • addContract: The function we added to the Company constructor prototype.
  • constructor: The constructor function used to create the object. In this case our Company constructor function.
  • Another internal prototype object. The rabbit hole gets deeper here. Forget this for now, I will discuss it in a future post about object inheritance.

As you can see, any property added to a constructor function’s prototype will exist on the internal __proto__ of any objects created using that constructor function. Taking addContract as an example, when you call company.addContract() JavaScript will search the company instance looking for an addContract function. When it doesn’t find it, JavaScript will then search the instance’s __proto__ in the same way. This time it finds the function, and executes it.

Object Creation

So what exactly happens when we call new Company()? The following:

  • A new empty object is created
  • The internal prototype (__proto__) of the object is set to be the external prototype of Company (Company.prototype), allowing the object to inherit all of the properties from the Company prototype.
  • The constructor function Company() is executed in the context of the new object. That just means that ‘this’ within the body of the function now contains the new object that was created. This is how we add all the properties like id, name, address, etc to the new object.
  • The new object is returned by the function. We now have a company instance to use.

In the next part of the series I’ll discuss how inheritance is implemented in JavaScript.

* People in the know are maybe saying I’m wrong since the class keyword was introduced in ES6. I will discuss this in a later post, and explain why these aren’t really classes.

Full Series

Leave a Reply

Your email address will not be published. Required fields are marked *