DEV Community

Cover image for How JavaScript Tries to Imitate Classes and Is There a Better Way?
PabloHoudini
PabloHoudini

Posted on

How JavaScript Tries to Imitate Classes and Is There a Better Way?

How JavaScript Tries to Imitate Classes and Is There a Better Way?

JavaScript, undoubtedly, can be a very confusing language, especially for those coming from traditional class-based languages like Java or C#. When JavaScript was first created by Brendan Eich, there was an intention to make it look somewhat like Java. This has led to some interesting design choices, particularly around how JavaScript handles object-oriented programming (OOP).

Today, I would like to take a quick look under the hood and see what is going on with JavaScript's approach to classes and prototypes.

The Evolution of Classes in JavaScript

Before the introduction of the class keyword in ES6 (ECMAScript 2015), JavaScript developers used constructor functions to create objects and simulate class-like behavior. Here’s a simple example:

// Constructor function
function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.greet = function() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

const john = new Person('John', 30);
john.greet(); // Output: Hello, my name is John and I am 30 years old.
Enter fullscreen mode Exit fullscreen mode

In this example, Person is a constructor function, and we add methods to its prototype. This allows all instances of Person to share the same method, saving memory.

The Introduction of the class Keyword

With ES6, JavaScript introduced the class keyword, which provides a cleaner and more familiar syntax for creating objects and handling inheritance. However, under the hood, classes in JavaScript are still based on prototypes.

// Class syntax
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    greet() {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
}

const jane = new Person('Jane', 25);
jane.greet(); // Output: Hello, my name is Jane and I am 25 years old.
Enter fullscreen mode Exit fullscreen mode

Despite the syntactic sugar, the class keyword in JavaScript does not introduce a new object-oriented model. It simply provides a more convenient way to work with prototypes.

Understanding Prototypes

In JavaScript, every object has a hidden internal property called [[Prototype]] that points to another object. This is known as the prototype chain. When you try to access a property on an object, JavaScript will look up the prototype chain until it finds the property or reaches the end of the chain.

const animal = {
    eats: true
};

const rabbit = {
    jumps: true,
    __proto__: animal
};

console.log(rabbit.eats); // true
console.log(rabbit.jumps); // true
Enter fullscreen mode Exit fullscreen mode

In this example, rabbit inherits the eats property from animal through the prototype chain.

Classes vs. Prototypes: What’s the Difference?

While classes provide a more structured and organized approach, prototypes offer more flexibility and control. Here’s a comparison:

Classes

  • Syntax: Cleaner and more intuitive, especially for developers from class-based languages.
  • Readability: Easier to read and understand.
  • Inheritance: Uses the extends keyword for inheritance.

Prototypes

  • Flexibility: More control over the inheritance chain.
  • Memory Efficiency: Methods are shared across instances.
  • Compatibility: Supported in all JavaScript environments, including older ones.

Real-Life Code Samples

Using Classes

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

    speak() {
        console.log(`${this.name} makes a noise.`);
    }
}

class Dog extends Animal {
    speak() {
        console.log(`${this.name} barks.`);
    }
}

const dog = new Dog('Rex');
dog.speak(); // Output: Rex barks.
Enter fullscreen mode Exit fullscreen mode

Using Prototypes

function Animal(name) {
    this.name = name;
}

Animal.prototype.speak = function() {
    console.log(`${this.name} makes a noise.`);
};

function Dog(name) {
    Animal.call(this, name);
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.speak = function() {
    console.log(`${this.name} barks.`);
};

const dog = new Dog('Rex');
dog.speak(); // Output: Rex barks.
Enter fullscreen mode Exit fullscreen mode

Conclusion

JavaScript's approach to OOP through prototypes and the class keyword provides developers with powerful tools to create and manage objects. While classes offer a more familiar and organized syntax, understanding prototypes is crucial for mastering JavaScript. Both methods have their own advantages, and a good JavaScript developer should be comfortable using both, depending on the requirements of the project.

By understanding the underlying mechanics of prototypes, you can write more efficient and maintainable code, leveraging the full potential of JavaScript's object-oriented capabilities.

Top comments (0)