Skip to main content

ES6 Classes: Class Syntax – Prototypes in Disguise

Spruce EmmanuelFebruary 18, 2025About 4 minJavaScriptArticle(s)blogfreecodecamp.orgjsjavascript

ES6 Classes: Class Syntax – Prototypes in Disguise 관련

How to Use Classes in JavaScript – A Handbook for Beginners

Are you curious about classes in JavaScript but feel a little puzzled about how they work or why you'd even use them? If that's you, then you're definitely in the right place. Lots of developers find classes a bit tricky at first, and honestly, I was...

How to Use Classes in JavaScript – A Handbook for Beginners
Are you curious about classes in JavaScript but feel a little puzzled about how they work or why you'd even use them? If that's you, then you're definitely in the right place. Lots of developers find classes a bit tricky at first, and honestly, I was...

Okay, we've wrestled with constructor functions and call() and Object.create() to get inheritance working with prototypes. It's powerful, but let's be honest, it can feel a little verbose and indirect, especially if you're used to class-based languages.

That's where ES6 classes come to the rescue. They offer a much more streamlined and class-like syntax for creating object blueprints in JavaScript.

Let's rewrite our PersonConstructor example using the class syntax. Get ready for a breath of fresh air.


PersonClass - Constructor Function Reimagined as a Class

Here's how we can define our Person blueprint as a class:

class PersonClass {
  //  Using the 'class' keyword!
  constructor(name, age) {
    //  'constructor' method - like our old constructor function
    this.name = name; //  Still using 'this' in the constructor
    this.age = age;
  }

  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
}

Doesn't that look much cleaner and more organized? Let's break down the class syntax:


Creating Objects from a Class - Still Using new

To create objects from our PersonClass blueprint, we still use the new keyword, just like we did with constructor functions:

const classPerson1 = new PersonClass("Charlie", 28);
const classPerson2 = new PersonClass("Diana", 32);

console.log(classPerson1.name); // Output: Charlie
classPerson1.greet(); // Output: Hello, I'm Charlie

Yep, it works exactly the same way as our constructor function example, but the class syntax is just much more readable and less cluttered.


DeveloperPersonClass - Inheritance Made Easy with extends

Now, let's tackle inheritance using classes. Remember how we had to use call() and Object.create() to get DeveloperPersonConstructor to inherit from PersonConstructor? With classes, inheritance becomes super straightforward using the extends keyword.

Here's how we can rewrite DeveloperPersonConstructor as a DeveloperPersonClass that inherits from PersonClass:

class DeveloperPersonClass extends PersonClass {
  //  'extends' for inheritance!
  constructor(name, age, programmingLanguage) {
    super(name, age); //  'super()' calls the parent class constructor!
    this.programmingLanguage = programmingLanguage;
  }

  code() {
    // Developer-specific method
    console.log(`${this.name} is coding in ${this.programmingLanguage}`);
  }
}

Look at that. Inheritance in classes is declared using the extends keyword: class DeveloperPersonClass extends PersonClass {...}. This line alone says, "Hey JavaScript, DeveloperPersonClass should inherit from PersonClass."

Inside the DeveloperPersonClass constructor, we have this line: super(name, age);. super() is crucial for class inheritance. It's how we call the constructor of the parent class (PersonClass in this case). When we call super(name, age), it's essentially doing the same thing as PersonConstructor.call(this, name, age) in our constructor function example—it's running the PersonClass constructor to set up the inherited properties (name and age) on the DeveloperPersonClass object.

After calling super(), we can then add any developer-specific properties or methods to our DeveloperPersonClass, like this.programmingLanguage = programmingLanguage; and the code() method.


Using DeveloperPersonClass - Inheritance in Action, Cleaner Syntax

Let's create a DeveloperPersonClass object and see inheritance in action with this cleaner syntax:

const classDevPerson1 = new DeveloperPersonClass("Eve", 35, "JavaScript");

console.log(classDevPerson1.name);
//
// Eve (Inherited from PersonClass!)
console.log(classDevPerson1.age);
//
// 35 (Inherited from PersonClass!)
classDevPerson1.greet(); 
//
// Hello, I'm Eve (Inherited from PersonClass!)
console.log(classDevPerson1.programmingLanguage);
//
// JavaScript (Developer-specific)
classDevPerson1.code(); 
//
// Eve is coding in JavaScript (Developer-specific)

It works exactly as expected. classDevPerson1 inherits name, age, and greet() from PersonClass and also has its own programmingLanguage and code() methods. But the class syntax makes the inheritance relationship much more obvious and easier to work with.


Classes: Syntactic Sugar, Prototype Power Underneath

Let's be crystal clear again: JavaScript classes are syntactic sugar over prototypes. They are a more user-friendly way to write code that is still based on prototypes and constructor functions behind the scenes.

When you define a class, JavaScript is actually doing these things for you under the hood:

Classes don't change the fundamental prototype-based nature of JavaScript OOP. They just give us a more familiar and less verbose syntax to work with it.


So, Are Classes Just "Fake" Classes?

Some people argue that JavaScript classes are “fake” because they’re merely syntactic sugar. But honestly, that’s not the point at all. Syntactic sugar is awesome—it makes our code easier to read, write, and maintain. For those coming from a class-based language background, classes make object-oriented programming in JavaScript much more approachable and understandable.

The key takeaway is that while classes give you a neat, familiar syntax, you still need to understand the underlying mechanism: prototypes. Classes are just a friendly layer on top of JavaScript’s prototype system.