A Matter of Class

June 05, 2017 0 Comments

A Matter of Class

 

 

Introduced by the ECMAScript 2015 specifications, the class construct has become part of the official JavaScript syntax. 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 PrototypeExtJSDojoBackboneEmber, and others. TypeScript itself was born with the aim of bringing class-based object-oriented programming to the 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.’); }
}

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.’);
};

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.’); }
}

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.’);
};

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

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 is 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

The definition of AnimalSnake, 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

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 worse, 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.’);
};

We have redefined the structure of a Horse as if it were 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.


Tag cloud