About two years ago the ECMAScript 2015 specification1 introduced classes to JavaScript. I cannot speak for you, but for me it took a while to get my head around the concept of prototypes when first starting JavaScript. Then lectures at university taught me the basic concepts of object oriented programming and everything was fine. The two worlds were completely separate for me. ES6 seems to break this clear distinction and makes it look like classic OOP is coming to JavaScript in the form of keywords like class, super and extends. That is not the case. These keywords are syntactic sugar for things that already exist within the prototype world of JavaScript. Until now I just lived with the abstraction layer and used these features where I was forced to: ES6 React components. But now I want to find out more about them and what they actually are and do.

There are no classes, just functions

There are a few important differences between what one might think what a class is, and what a ES6 class really is:

// A class is a function
class A {}
console.log(typeof A) // 'function'

// Just like function expressions, there are class expressions
const D = class {}

// But also named classes can be referenced by variables
const E = class F {}
console.log( E.name ) // 'F'
console.log( F ) // Uncaught ReferenceError: F is not defined

So a class is really just a function that can be assigned to variables, passed to functions, returned from functions and so on. In fact since functions are objects as well, a class is an object too. Okay that sounds confusing so let us not focus too much on terminology but agree on the fact that classes are not the abstract blueprints from classic OOP, but actual entities within your program, namely function objects. There are still a few differences to regular functions though. One of them that is definitely worth remembering is:

// Functions are hoisted
v() // 'On top'
function v() { return 'On top' }

// Classes are not
const c = new C() // Uncaught ReferenceError: C is not defined
class C {}

Alright, they are functions. What do they do?

Now that we figured how classes are just functions the next step in exporing is to call them. This leads to the next difference between classes and functions: A class can only be invoked with the new keyword. This keyword can be put before any function invocation, to assign a fresh object to this that will be returned by default. This way we could make functions act like constructors in a pre-ES6 environment. But this constructor pattern is based on conventions and not enforced by the language semantics. Such a fake constructor can also be called without the new keyword and modify whatever the this context of that current invocation is. That is a problem and as far as I understand, the class syntax aims to fix that by requiring a new:

class X {}
X() // Uncaught TypeError: Class constructor X cannot be invoked without 'new'
const x = new X()
console.log( x.constructor ) // class X {}

Just like in the “old” constructor pattern, the new keyword sets the constructor property of the created object to the function it was invoked with. But somehow the goal of a class or constructor should be to help objects share code, right? Since we have seen that this stuff is mostly just new syntax and JavaScript uses prototypes for behavior delegation, this is probably what happens. Indeed:

class A {
	method() {}
}

const a = new A()
Object.getPrototypeOf( a ) // Object {constructor: function, method: function}

That means class methods are shared via the prototype object that is set on instances by the new keyword. That is exactly how it was done before by manually adding functions to A.prototype. So far class methods add zero language features, but simply provide a nicer syntax for a common pattern. Now what about instance properties? The old constructor pattern would add these onto this inside the constructor function. ES6 classes have a magic method called constructor that is used to create new instances:

class A {
	constructor( value = 0 ) {
		this.value = value
	}
}

const a = new A() // A {value: 0}
const b = new A(3) // A {value: 3}

ES6 classes are nothing fancy, just new syntax for old prototypes

What I am trying to point out is: No classes in the classical OOP sense were added to JS. Everything is still based on prototypes. That is good news, because it means that it is mainly new syntax instead of concepts to learn. An ES6 class is a function that is used to create new objects with a predefined prototype that has certain methods. It is a replacement for the old constructor pattern, which was enforced by convention and not by language semantics. There are more features like inheritance and the super keyword that I have not looked at in detail yet. But understanding the points above should be a decent foundation for this step.