
Object Oriented Programming in Javascript
Everybody loves Object Oriented Programming (OOP). Hiding implementation details to decrease complexity? Less rewriting code? More maintainable projects? Count me in! Javascript isn’t the most straightforward path to learning how to write object oriented programs. I started out learning programming concepts in Swift; the static typing and straightforward syntax made more complex OO concepts so much easier to grasp. So when I, a mere newbie, dove into object oriented Javascript, I was like:

It was markedly different from any other language I’d looked at up to that point. Also, there’s a lot of really badly written JS out there, and many quick fixes from Stack Overflow can bite you in the ass on complex projects. So I decided to write this post with hopes to save others from the same confusion that I experienced. Note to reader: this article assumes you know the basics of object oriented programming. If you don’t know anything about object oriented programming or it’s benefits, read this article first!
Constructing Objects
There are a surprising amount of ways you can create objects in JS. This is one of the things that confuses many at first. I’ll go through the basic methods of creating objects and discuss the pros and cons of each.
- Object Literals
Good old object literals. No weird syntax here:
var objectLiteralPerson = { // setting property name: "Bob Benson" , // declare function
greet () {
// 'this' refers to current object
console.log("Hello, I'm " + this.name);
}}
The advantages of using object literals to create objects include convenience, flexibility in declaration, and less code during declaration. You can drop an object literal anywhere in your program with no previous setup and it’ll work, which can be very handy! There are definitely issues with object literals though. If you want to create two similar objects, you have to copy and paste the methods and properties and edit what you need changed. This duplicates the amount of memory used and the size of your program - this isn’t ideal for memory usage or maintainability. The best use of object literals is to create a unique group of related functionality and properties that won’t be reused in a similar way anywhere else in your program.
- Factory Functions
Factory functions are a good way to more effectively group properties and functionality into objects. They’re basically just functions that return an object. Check it out:
function createPerson(name){
return {
name: name,
greet: function() {console.log("Hello, I'm" + this.name);}
}
}var person = createPerson("Jack Johnson");
Here, createPerson(name)
returns an object literal that can now be used as a normal object. This method of creating objects beats out using raw object literals because you don’t have to copy and paste all the functions and properties of an object every time you want to declare a new instance of it. You can pass parameters to easily tweak objects you want to reuse with different properties. Factory functions provide an element of re-usability while retaining a lot of the flexibility you get with object literals.
- Constructor Functions
These functions are the most conventional way to create objects that use functionality from each other using prototypal inheritance. What is prototypal inheritance, you ask? Let me show you using constructor functions. Take the Person
object from the last two examples:
function Person(name) { // 1
this.name = name; this.greet = function() { console.log("Hello, I'm " + this.name); }}//2
var person = new Person("Jack Johnson");
//3
console.log(Object.getPrototypeOf(person)); // Person {}
Here is where it gets interesting. I’ll walk through the steps to explain exactly what happens with the new
and this
keywords.
this
refers to the object currently within the scope of thePerson
function. It sets it’s own propertyname
as the value of the parameter passed into the function.- A new object
person
is created using the constructor function. When you usenew
, it binds a newly created object to thethis
keyword within the called constructor function. This binding allows theperson
object to reference all the functionality from within the constructor function. - The object we just created has a property called
prototype
, and the value is just thePerson
object template! So when you call a function likegreet()
from theperson
object, the browser checks theperson
object for the function. If it’s not in that object, the browser checks to see if it’s declared within theprototype
object that is a property of theperson
object. It goes up the “chain” of objects and their prototype properties until it either finds the function or doesn’t find it, which means the function is undefined. The prototype property is the place where inherited members are defined.
I know this can be super confusing. If you have any questions or would like clarity on how exactly prototypes work, please send me a message or comment and check out the docs at Mozilla. You have to think about it as object functionality being delegated to it’s prototype, instead of being copied from it’s superclass.
So why do I need to use constructor functions? Why can’t I just stick with factory functions? Well one concept of OOP is to write reusable and easily extendable code. Constructor functions allow us to do that by acting as the prototype/template for other objects, lending their functionality and properties to the object using it as a prototype. What if I want to make an extended version of a Person
? How about an Athlete
? Here’s how I would do it:
function Athlete(name,sport) { // 1
Person.call(this,name); this.sport = sport;}// Tip: declare your properties inside the constructor functions and methods on the prototype property, outside of the constructor.
Athlete.prototype.play = function() {
console.log(this.name + " is playing " + this.sport);
}// 2Athlete.prototype = Object.create(Person.prototype);// 3 Athlete.prototype.constructor = Athlete;var athlete = new Athlete("Serena Williams","Tennis");
athlete.greet(); // Hello, I'm Serena Williams
Here are the steps to implement prototypal inheritance with minimal verbosity:
- You pass the current object through the
Person
constructor function to gain it’s functionality. Then you set thesport
property that is only available toAthlete
objects.
2. Set the constructor function’s prototype to a new object created from the prototype of the object you want to inherit from (in this case person)
3. Thanks to Greg Pawlowski for pointing this one out — remember to set the constructor function appropriately for clarity on which constructor function is responsible for making the object.
Dynamic Updating
Steps 2 and 3 in the previous example allowed me to set up dynamic updating throughout the prototype chain. This means I can declare a function or property on the prototype of a constructor function after I declare an instance, and the instance is updated with that property or function. It works like this:
// Assume that the Athlete and Person constructor function are already defined abovevar athlete = new Athlete("MJ","Basketball")// I can declare a new method on the Athlete prototype and the instance I just created will update Athlete.prototype.play = function() { console.log("Playing " + this.sport);}athlete.play(): // Playing Basketball
What’s really cool is that I can dynamically update Athlete
instances by adding to the Person
prototype:
Person.prototype.walk = function() { console.log(this.name + " is walking");}athlete.walk(); // MJ is walking
Setting up this dynamic updating throughout the prototype chain gives you a lot of flexibility in extending objects and using inheritance to it’s maximum capabilities. Remember, to implement this you must set up the prototype properties like I did in the previous example.
These are three basic ways to make objects using Javascript! Although I went over those three ways, there are so many (it’s kind of ridiculous, actually) ways to declare objects in Javascript. If you’d like to know more about different instantiation patterns, check out this article from site point and this one from John Dugan.
- ES6 Classes
A discussion of OO in JS wouldn’t be complete without touching on ES6 classes! This is a huge step for the language, and it could lead to even wider adoption of Javascript. ES6 classes are going to remind you of declaring a class in more conventional OO languages. Here’s how you do it:
class Person { constructor(name){
this.name = name;
}
greet() {
console.log("Hello, I'm " + this.name);
}}
// To implement inheritance class Athlete extends Person {
// You have to call super() before you invoke "this"
constructor(name,sport) {
super(name)
this.sport = sport
}}
I bet you’re sick and tired of reading my confounding attempts at explaining what’s happening under the hood, so check out this article for more info on how to use ES6 classes optimally.
Now, I know it might be very tempting to go out and use your newfound knowledge of prototypal inheritance and other OO concepts in Javascript, but remember that it’s a tool to have in your belt, not a silver bullet. You most likely won’t want to use inheritance in smaller projects, because the added complexity isn’t worth the benefits.
The best situations to use classes and constructor functions lie in larger, complex programs where you need organized, maintainable, and simple code. Using the power of inheritance can make a huge difference in codebases of thousands of lines because it forces you to categorize functionality, organize the different components of your system, and modularize your code into well-defined objects.
Thanks for reading! If it helped you at all, a few claps would be greatly appreciated :) Also, I apologize for the poorly formatted code… Does anybody know how to solve that issue? Because formatting code in medium is possibly the single biggest obstacle for me in creating blog posts. Thanks in advance.
✉️ Subscribe to CodeBurst’s once-weekly Email Blast, 🐦 Follow CodeBurst on Twitter, view 🗺️ The 2018 Web Developer Roadmap, and 🕸️ Learn Full Stack Web Development.