Learn JavaScript OOP: A primer for web development

JavaScript may not be what comes to mind when someone mentions an OOP language, but the fact is it has great support for OOP - it just has its intricacies that need to be understood first.

If you're coding in JavaScript, getting familiar with OOP principles can make your life easier for a few reasons:

  • It's easier to debug your code when you use objects and classes.
  • You’re able to use techniques like encapsulation and inheritance.
  • You’ll have an easier time getting hired on a team using OOP principles for their code.

Here, you’ll learn the basics of Object-oriented JavaScript in ES5 and ES6 so that you can see the comparisons and how JavaScript has trended towards an OOP style. First, this post looks at OOP in ES5 and the basics you’ll need to know such as objects, constructor functions, and the syntax that is associated with accessing object properties.

Towards the back-half, the post will look at OOP in ES6 and the use of classes, prototype properties, and methods. If you’re interested in doing a deeper dive into OOP in JavaScript and the concepts mentioned throughout, you can check out Learn OOP in JavaScript.

What is OOP (Object-Oriented Programming)?

If you’re familiar with other languages such as C# and Java, then you’ve probably heard the term Object-Oriented Programming (OOP).

Object-oriented programming is a style of programming - not a tool - which is why even though it’s an older style, it’s still very popular and widely used. This style involves breaking a program into segments of objects that can communicate with each other. Each object is defined by its own set of properties, which can then be accessed and modified through various operations.

The above illustration is a real-world example of an employee record where each employee can be considered an “object”, and since every employee has a name, age, and designation, these can be considered the properties of that employee.

OOP in JavaScript (ES5)

OOP in JavaScript works differently than in other languages. So, if you’re familiar with OOP in other languages it’s important you put that knowledge aside for now since holding on to those concepts might confuse you.

You’ve probably seen that other languages such as C++, Java, and C#, use the keyword class to define a class. A class has properties and methods in it for every instance of that class. In this case, class acts as a blueprint for the object.

JavaScript differs from other languages because you can implement OOP without the use of classes (more on this later). Before introducing its ES2015 version, JavaScript still relied on prototype-based programming. In this programming style, the object encapsulates the properties, i.e., its methods and data, instead of a class. You can add new properties to this object at any time. So now, an object can be an individual instead of being an instance of the class, meaning if you want an object you easily just create one without having to create a class first.

Both Prototype-based and Class-based OOP have their advantages and disadvantages.

Prototype-based is more straightforward as you don’t need to create a blueprint beforehand which requires pre-planning about the sort of properties required before creating an object.

Since no class needs to be made, you can create the object directly. This also offers flexibility; hence, any changes to the objects can easily and quickly be made while they’re being used.

While all these advantages exist in Prototype-based programming, there is a higher risk of incorrectness as abrupt changes can easily be made. Whereas in the Class-based approach, the blueprints layout a plan beforehand, decreasing the chances of bugs arising.

Objects in JavaScript

Objects are a major part of JavaScript, as almost everything in it is an object. For example, functions, arrays, regular expressions, dates, and even data types like boolean and strings, if declared with the keyword new, can be considered a javascript object.

What is an object

In real-life, objects are found everywhere, so these real-life scenarios can also be mapped into object-oriented code.

Let’s take a look at an example of how Objects are used:
Assume you have three shapes which you need to find the area of: square, rectangle and circle.

If you were to write code that would calculate the area of each, what would you do?

In an OOP style, you’d convert the code by creating objects for each shape: square, rectangle, and circle. Here, each object has its own set of properties which include:

  • data values
  • functions

We need the length, width, and the radius. These values will be encapsulated in the object of that particular shape.

Similarly, a function to calculate the area will also be required. This will also be encapsulated in the object as a part of its properties.

How to create an object literal

An object literal can be created:

  • using the figure brackets {...} in the declaration.
  • using the new keyword.
  • based on an existing object by using the create() method.

All of these approaches do exactly the same thing.

Here’s what the syntax looks like:

Using figure brackets

var objectName = { 
 
 //properties defined
 propertyName1 : propertyValue1,
 propertyName2 : propertyValue2,
 functionName() {}
 
}

Using the new keyword

var objectName = new Object()

Using create() method

var newObjectName = Object.create(existingObjectName)

Accessing properties of an object

There are various ways to access object properties. Outlined are a couple of popular ways, but you can also iterate over object properties using the for..in loop and you can also access properties of a nested loop (to implement this all that is required is to use the dot operator, but you’ll need to add one additional dot).

Dot operator (also useful for setting and deleting properties)
In JavaScript, an object literal can be accessed using the dot operator. To access any property, the name of the object should be mentioned first, followed by the dot operator, and then the name of the property encapsulated in that object.

Here we can see the syntax of the dot operator:

objectName.functionName()

Here’s an example of how to access properties using the dot operator:

//creating an object named shape

var shape = {
 //defining properties of the object
 //setting data values
 name : 'square',
 sides : 4

}

//accessing the properties using the dot operator
console.log("Name is:", shape.name) //using dot operator to access "name"
console.log("Number of sides are:", shape.sides) //using dot operator to access "sides"

Using square brackets (also useful for setting and deleting properties)
Another method to access values is by using the square brackets [ ]. The name of the property to be accessed is written inside the square brackets as a string.

Here we can see the syntax of the square brackets method:

objectName['functionName']()

Here’s an example of how to access properties using square brackets:

//creating an object named shape

var shape = {
 //defining properties of the object
 //setting data values
 name : 'square',
 sides : 4

}

//accessing the properties using square brackets
console.log("Name is:", shape['name']) //using square brackets to access "name"
console.log("Number of sides are:", shape['sides']) //using square brackets to access "sides"

Useful keywords: Get, Set, This

Get
The get keyword will bind an object property to a function. When this property is looked up now the getter function is called. The return value of the getter function determines which property is returned.

Set
The set syntax binds an object property to a function to be called when there is an attempt to set that property.

This
this keyword refers to an object so that you can access the properties within an object. It can also be used to set the value of a property within an object.

Functions as objects

Constructor functions

Functions are also objects in JavaScript. This is because just like objects, they have their own properties and methods. Functions can be used to construct objects as well, and these types of functions are known as constructor functions.

Constructor functions essentially eliminate the need to create separate object literals for similar tasks. They are useful because you'll often come across situations in which you don't know how many objects you will be creating; constructors provide the means to create as many objects as you need in an effective way.

Here is the syntax for implementing the constructor function:

function FunctionName(parameter1, parameter2,...){
   //all the properties of the object are initialized here
   //functions to be provided by objects are defined here
}

As can be seen from above:

  • The keyword function is used to define the function.
  • The constructor function name should be capitalized just like FunctionName in the above snippet.
  • The body of this function is basically the constructor part of the function as it initializes the properties by setting them equal to the respective parameters being passed into the function.

Here is an example of a constructor function:

function Employee(_name, _age, _designation){
  this.name = _name
  this.age = _age
  this.designation = _designation
}

Note that all the objects created from Employee will contain the properties name, age, and designation, where the keyword this can assign specific values even though they’re part of the same property.

Prototype objects

Prototype objects are a simpler approach for adding new methods/properties to a constructor function.

Prototype properties in objects

Aside from the properties that you create, there is an additional hidden property known as [[Prototype]] property that is present inside every object created from a constructor function. The prototype property either points to another object or is null.

Here is an example of using the Prototype property:

//Shape object

var Shape={
 name: 'Rectangle',
 sides: 4
}

//Rectangle object
var Rectangle = {
 length: 3,
 width: 5
}

//setting [[Prototype]] of Rectangle equal to Shape
Rectangle.__proto__ = Shape

//creating an object instance using Shape and Rectangle
console.log("Name of shape is:",Rectangle.name)
console.log("Number of sides are",Rectangle.sides)
console.log("Length is:",Rectangle.length)
console.log("Width is:",Rectangle.width)

Here we can see that when the prototype property of Rectangle is set to Shape, it is able to access all the properties in Shape. If a property is not found in the object, such as the name property is not found in Rectangle, JavaScript will automatically take it from the prototype of that object, Shape. This is known as prototypal inheritance where lines 20 and 21, are known as inherited properties; this is based on the concept of prototype chaining.

Object-oriented JavaScript in ES6

JavaScript ES6 offers some new features as well as improvements. One of those improvements that is the introduction of the keyword class. You can explore all the other nuances of ES6 here

Whereas in JavaScript ES5, function constructors were used to implement the concept of classes. However, in the ES6 version, the class keyword is used which cleans up the syntax for implementing the same concept, making it easier to understand.

Declaring a class in JavaScript ES6

The syntax is as follows:

class ClassName {
  constructor() {
    //initializing class properties
  }
  //class methods defined
}

One of the differences between the constructor function and class-based implementation is that, in the former, the body of the function acts as the constructor, where all the properties are defined, whereas, in the latter, there is a separate constructor function defined inside the class used to initialize the properties.

Creating an object instance from a class

Here we can see an example of how to create an object instance from a class:

//creating a class named employee
class employee{
 //creating the constructor function
 constructor(name,age,designation){
   //all properties defined as they were in the constructor function
   this.name = name
   this.age = age
   this.designation = designation
   this.displayName = function() {
     console.log("Name is:",this.name)
   }
 }
}

//creating an object instance named "employeeObj"
var employeeObj = new employee('Joe',22,'Developer')
//displaying the properties of employeeObj
employeeObj.displayName()
console.log("Age is",employeeObj.age)
console.log("Designation is:",employeeObj.designation)

Since employee is a constructor function itself, the method to create an object instance from a class is exactly the same as that in the ES5 version. The new keyword is used to initialize a new object, employeeObj. The constructor method then runs for this object assigning the values passed into it to the properties.

Defining methods in a class

Whenever a method is declared inside a class, it is defined on the prototype of that class. Meaning, whenever an object instance accesses it, it gets taken from the respective class’s prototype.

Here is an example:

//creating a class named employee
class employee{
 //creating the constructor function
 constructor(name,age,designation){
   //all properties defined as they were in the constructor function
   this.name = name
   this.age = age
   this.designation = designation
   this.displayName = function() {
     console.log("Name is:",this.name)
   }
 }
 //defining methods in a class
 //getAge method returning the age of the current object
 getAge(){
   return this.age
 }
}

Here’s what’s happening in the code above:

  • The getAge function is being defined outside of constructor function in line 15.
  • All such methods are stored in the prototype object of employee.
  • So, a new object, such as employeeObj, has access to all the methods defined in the class.
  • When called by employeeObj the method getAge is taken from employee.prototype.

Next Steps

Although JavaScript may not be considered an OOP language, the use of version ES6 (because of the use of classes) will give you a feel of what it’s like to code in a more traditional OOP programming language such as C/C++. The major differences between ES5 and ES6 is the addition and clean-up of syntaxes.

This post has just scratched the surface of Object-oriented JavaScript. There is much more to cover: static methods, protecting properties, and data encapsulation to name a few. If you’re interested in going into more detail, you can learn all the essentials with OOP in JavaScript.

Show Comments