DEV Community

Cover image for A matter of class: examining the class construct in JavaScript
Andrea Chiarelli
Andrea Chiarelli

Posted on • Edited on

A matter of class: examining the class construct in JavaScript

This article was originally published on my Medium profile

It is more than one year and half since the class construct has become part of the official JavaScript syntax. Introduced by the ECMAScript 2015 specifications, this construct has been enthusiastically welcomed by many developers. Indeed, it has been considered a sign of the formalization of various attempts to simulate classes, inheritance and other Object-Oriented features offered for several years by many libraries, such as Prototype, ExtJS, Dojo, Backbone, Ember and others. TypeScript itself was born with the aim of bringing the class-based Object-Oriented programming in JavaScript language. However the class construct may lead to serious misconceptions about the Object-Oriented nature of JavaScript. Let's analyze why.

A convenient construct

Using the class construct is very handy. Just take a look at the following code to define the Animal class:

class Animal {
  constructor(name, legsNumber) {
    this.name = name;
    this.legsNumber = legsNumber;
  }

  speak() {
    console.log(this.name + ‘ makes a noise.');
  }
}
Enter fullscreen mode Exit fullscreen mode

Now let's compare it with the equivalent ECMAScript 5 code:

var Animal = function (name, legsNumber) {
  this.name = name;
  this.legsNumber = legsNumber;
};

Animal.prototype.speak = function() {
  console.log(this.name + ‘ makes a noise.');
};
Enter fullscreen mode Exit fullscreen mode

The class construct provides a much more compact code. It appears self-contained and familiar to people who have a traditional Object-Oriented programming background.

The convenience of this construct becomes even more noticeable when we use inheritance, as we can see by analyzing the following code where the Snake and Horse classes are defined by deriving from Animal:

class Snake extends Animal {
  constructor(name: string) {
    super(name, 0);
  }

  speak() {
    console.log(this.name + ‘ hisses.');
  }
}

class Horse extends Animal {
  constructor(name: string) {
    super(name, 4);
  }

  speak() {
    console.log(this.name + ‘ whinnies.');
  }
}
Enter fullscreen mode Exit fullscreen mode

Let's consider now the respective definitions with the dear old ECMAScript 5:

var Snake = function (name) {
  Animal.apply(this, [name, 0]);
};

Snake.prototype = Object.create(Animal.prototype);
Snake.prototype.constructor = Snake;
Snake.prototype.speak = function() {
  console.log(this.name + ‘ hisses.');
};

var Horse = function (name) {
  Animal.apply(this, [name, 4]);
};

Horse.prototype = Object.create(Animal.prototype);
Horse.prototype.constructor = Horse;
Horse.prototype.speak = function() {
  console.log(this.name + ‘ whinnies.');
};
Enter fullscreen mode Exit fullscreen mode

The convenience of using the class construct seems clear: in addition to a smaller number of statements we get a greater readability and a similarity to the syntax of most Object-Oriented programming languages. Anyway, regardless of the definition used, in both cases we will use the classes and constructor functions in the same way:

var kaa = new Snake(Kaa the Python);
var fury = new Horse(Fury the Horse);

console.log(kaa.legsNumber);    //0
console.log(fury.legsNumber);   //4
Enter fullscreen mode Exit fullscreen mode

This ensures the maximum interoperability between the old and the new approach.

Not everyone is happy

Despite its convenience, however, not all developers are so excited about the introduction of the class construct. It looks familiar to most programmers, and gives the illusion of using a class-based Object-Oriented programming language such as Java and C #.

But that is the whole point: it is an illusion, a dangerous illusion. Contrary to what might seem, ECMAScript 2015 specifications have not introduced the concept of class in JavaScript. JavaScript is and remains a prototype-based Object-Oriented programming language, even with the class construct.

The introduction of this construct in JavaScript syntax seems to extend the chain of errors that characterized the definition of this language: from the choice of the name itself, that has caused (and still causes) a bit of confusion with Java, to the use of the new keyword to create objects, actively contested by Douglas Crockford.

The main effect of these choices is that programmers are misguided in the real understanding of the language and are led to blame it because its behavior is not what expected.

Is it a real class?

But what is the difference between the class construct in class-based languages and the one in JavaScript? As we said, JavaScript is still a prototype-based language, so the class construct is just syntactic sugar for creating constructor functions in a more compact way. If we try to get the type of a class, we will find that it is not but a function:

console.log(typeof Animal);   //function
Enter fullscreen mode Exit fullscreen mode

The definition of Animal, Snake and Horse by using the class construct has the same effect of its definition by using the old ECMAScript 5-style code. Objects are not created by referencing a class, but by referencing a prototype, that is another object, as usual in JavaScript. This means that we can dynamically change the structure of our objects without involving its original class. For example, we can write the following code:

fury.wingsNumber = 2;

console.log(fury instanceof Horse);   //true
Enter fullscreen mode Exit fullscreen mode

We add a couple of wings to our Horse object, and it continues to be a horse. That's perfectly legal in JavaScript, but it is very difficult to implement and to understand in a class-based world.

Even worst, we can overturn the whole structure of our Horse object as follows:

var furySnake = new Horse();

furySnake.legsNumber = 0;
furySnake.speak = function() {
  console.log(this.name + ‘ hisses.');
};
Enter fullscreen mode Exit fullscreen mode

We have redefined the structure of a Horse like if it was a Snake, but it still remains an instance of the Horse class.That's out of any definition of class, not only in the context of programming languages, but also in philosophy and set theory contexts.

For example, from a mathematical point of view, a class is a collection of objects that can be unambiguously defined by one or more properties that all its member share. Clearly, since fury and furySnake share no properties, they cannot belong to the same (conceptual) class. Also from a class-based Object Oriented point of view the two objects can't belong to the same class.

Conclusion

Maybe the choice of a name other than class would have sounded strange to developers coming from languages like Java, C# and C++, but it would have created fewer illusions and disappointments.

In any case, now the die is cast. The important thing is that the JavaScript developer is aware of what class really means. You have been warned…

Andrea Chiarelli is the author of Mastering JavaScript Object Oriented Programming (Packt Publishing).

Top comments (1)

Collapse
 
vsaulis profile image
Vladas Saulis

Exactly! Class is a syntactic sugar. And I have it in mind when programming in JS.
Nice explanation!