Skip to main content Accessibility Feedback

Classes vs. prototypes in JavaScript

One of the core technologies in creating a Web Component is JavaScript classes.

customElements.define('my-component', class extends HTMLElement {
	// ...
});

I’ve been talking a lot lately about Web Components, and one of the things a lot of students have mentioned is that they find JavaScript classes confusing.

I used to, too! So today, I wanted to demystify them a bit. Let’s dig in!

Quick aside: I can create custom Web Components for your project or teach you how to write your own.

Prototypes and Object-Oriented Programming (OOP)

In JavaScript, every object has a prototype. This is a collection of properties and methods that are shared by all instances of that object.

For example, the Array.prototype.map() method is a method on the Array object’s prototype. Every array that you create automatically has that method as a property it can use.

let wizards = ['Merlin', 'Ursula', 'Gandalf'];
wizards.map(function (wizard) {
	return `${wizard} is awesome!`;
});

Creating your own prototype methods and properties

Let’s imagine you’re creating a DOM manipulation library, like a tiny jQuery, that accepts an element selector and let’s you manipulate all of those elements.

You’d start by create a constructor function. These should always start with capital letters.

function TinyJQuery (selector) {
	// ...
}

Users can create an instance using the new TinyJQuery() constructor, and pass in a selector for their elements.

let elems = new TinyJQuery('.sandwich');

In our constructor function, we’ll pass the selector into the querySelectorAll() method to find all matching elements, and assign it to the elems property for our instance.

Using this type of pattern, the this keyword becomes a reference to the current instantiation of the library (the thing you created using new).

function TinyJQuery (selector) {
	this.elems = document.querySelectorAll(selector);
}

Now, we can attach any methods we want all instances to have to the TinyJQuery.prototype. Inside these methods, this is again a reference to the current instance, which means we can use it to get properties like this.elems.

For example, here’s a forEach() method we can use to loop over each item. It accepts a callback function (fn) that runs code on each item.

function TinyJQuery (selector) {
	this.elems = document.querySelectorAll(selector);
}

TinyJQuery.prototype.forEach (fn) {
	for (let elem of this.elems) {
		fn(elem);
	}
}

Now, users can do stuff like this…

let elems = new TinyJQuery('.sandwich');

elems.forEach(function (elem) {
	elem.classList.add('mayo');
});

Now, let’s look at Classes.

JavaScript Classes

JavaScript Classes provide a simpler pattern for building objects and attaching methods and properties to their prototype.

Using TinyJQuery as an example, we’d first create a new Class like this…

class TinyJQuery {
	// ...
}

Inside it, we include a constructor() function that literally becomes the constructor. Because Classes are objects, we can use the object property shorthand for them.

class TinyJQuery {
	
	constructor (selector) {
		this.elems = document.querySelectorAll(selector);
	}

}

To attach methods to the prototype, we add them to the class.

We don’t need to include the library name or prototype. They just automatically get attached.

class TinyJQuery {
	
	constructor (selector) {
		this.elems = document.querySelectorAll(selector);
	}

	forEach (fn) {
		for (let elem of this.elems) {
			fn(elem);
		}
	}

}

This code does the same stuff as the OOP example above.

let elems = new TinyJQuery('.sandwich');

elems.forEach(function (elem) {
	elem.classList.add('mayo');
});

Why use Classes?

Classes provide a nice wrapper around your code, and can make things easier to both read and author.

They also provide some features that traditional OOP lacks. For example, in a JavaScript Class you can make properties and methods private, meaning they can only be read and used inside the class.

While traditional OOP methods still work just fine, I tend to reach for Classes for all of my library development now.