JavaScript class expressions provide another way to create classes. Unlike a class declaration, which starts with the class keyword as a statement, a class expression is used as an expression and produces a class value that can be assigned to a variable, passed to a function, or returned from another function. Class expressions can be anonymous or named, and they support constructors, methods, inheritance, and static members just like class declarations.

What Is a Class Expression in JavaScript?

A class expression is a way to define a class where the class definition is part of an expression. The result of evaluating the expression is a class constructor that you can use to create objects with the new operator.

Class expressions were introduced in ECMAScript 2015 (ES6), along with JavaScript classes. They are useful when a class needs to be created dynamically, assigned to a variable, returned by a function, or passed as an argument.

Basic Syntax of a JavaScript Class Expression

You can assign a class expression to a variable. The class body can contain a constructor and methods that define the behavior of its instances.

const Person = class {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  introduce() {
    return "My name is " + this.name + " and I am " + this.age + ".";
  }
};

const person1 = new Person("Nadia", 25);

console.log(person1.name);        // "Nadia"
console.log(person1.introduce()); // "My name is Nadia and I am 25."

In this example, the class expression creates a class value and assigns it to the Person variable. You can then use new Person() to create an instance. The variable name is not followed by a class declaration; it receives the value produced by the expression.

Anonymous Class Expressions

An anonymous class expression does not have a class name after the class keyword. The class value is commonly assigned to a variable, which provides a convenient way to refer to the class later.

const Car = class {
  constructor(brand) {
    this.brand = brand;
  }

  start() {
    return this.brand + " is starting.";
  }
};

const car1 = new Car("Toyota");

console.log(car1.start()); // "Toyota is starting."

Here, the class expression itself has no name. Because it is assigned to Car, JavaScript can infer the function’s name from that variable in this context. You can check the constructor’s name with Car.name.

Named Class Expressions

A named class expression includes an identifier after the class keyword. This name is available inside the class body, but it does not create a variable with that name in the surrounding scope.

const Vehicle = class Car {
  constructor(brand) {
    this.brand = brand;
  }

  getType() {
    return Car.name;
  }
};

const vehicle1 = new Vehicle("Honda");

console.log(vehicle1.brand);     // "Honda"
console.log(vehicle1.getType()); // "Car"
console.log(Vehicle.name);       // "Car"

// Car is not defined outside the class expression

In this example, Car is the internal name of the class expression. It can be referenced from inside the class body, such as in its methods. Outside the class expression, use the variable Vehicle. The identifier Car is not available as a surrounding variable.

Class Expression vs. Class Declaration

Both class expressions and class declarations define classes, and both support constructors, instance methods, static methods, and inheritance. The main difference is how the class value is introduced into the surrounding code.

Class Declaration Example

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

  study() {
    return this.name + " is studying.";
  }
}

const student1 = new Student("Rahim");

console.log(student1.study()); // "Rahim is studying."

Class Expression Example

const Student = class {
  constructor(name) {
    this.name = name;
  }

  study() {
    return this.name + " is studying.";
  }
};

const student1 = new Student("Rahim");

console.log(student1.study()); // "Rahim is studying."

The declaration introduces a class binding named Student. The expression creates a class value and assigns it to the variable Student. Class declarations are not usable before their declaration is evaluated because class declarations have temporal-dead-zone behavior. A class expression assigned to a const or let variable is likewise unavailable before that variable is initialized.

Using Class Expressions in Functions

Because a class expression produces a value, a function can return it. This allows you to create classes based on function arguments or other runtime conditions.

function createUserClass(role) {
  return class {
    constructor(name) {
      this.name = name;
      this.role = role;
    }

    describe() {
      return this.name + " is a " + this.role + ".";
    }
  };
}

const Admin = createUserClass("administrator");
const Editor = createUserClass("editor");

const admin1 = new Admin("Ava");
const editor1 = new Editor("Rafi");

console.log(admin1.describe());  // "Ava is a administrator."
console.log(editor1.describe()); // "Rafi is a editor."

The createUserClass() function returns a new class expression. The returned class closes over the role parameter, so each generated class can use the role value supplied when the function was called.

Using Class Expressions with Inheritance

Class expressions support inheritance through the extends keyword. The value after extends must evaluate to a valid constructor or null. This means a class expression can extend a class stored in a variable or returned by a function.

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

  speak() {
    return this.name + " makes a sound.";
  }
}

const Dog = class extends Animal {
  speak() {
    return this.name + " barks.";
  }
};

const dog1 = new Dog("Buddy");

console.log(dog1.speak()); // "Buddy barks."

The Dog class expression extends Animal, so instances of Dog inherit the constructor behavior and other accessible members from Animal. The speak() method is overridden to provide dog-specific behavior.

Using a Function to Provide a Base Class

You can use an expression after extends, including a function call that returns a class. This pattern is often used to build mixins that add reusable behavior to a base class.

const withTimestamp = Base =>
  class extends Base {
    setCreatedAt() {
      this.createdAt = new Date();
    }
  };

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

const TimestampedUser = withTimestamp(User);

const user1 = new TimestampedUser("Nadia");
user1.setCreatedAt();

console.log(user1.name);                    // "Nadia"
console.log(user1.createdAt instanceof Date); // true

The withTimestamp() function receives a base class and returns a class expression that extends it. The resulting class inherits the original behavior and adds a setCreatedAt() method. This is a simple example of the mixin pattern.

Using Static Methods in Class Expressions

Class expressions can also define static methods. A static method belongs to the class itself rather than to individual instances, so you call it using the class variable.

const Calculator = class {
  static add(a, b) {
    return a + b;
  }

  static multiply(a, b) {
    return a * b;
  }
};

console.log(Calculator.add(10, 5));      // 15
console.log(Calculator.multiply(4, 3)); // 12

In this example, add() and multiply() are static methods. You call them directly on Calculator; you do not need to create an instance with new Calculator().

When Should You Use Class Expressions?

Class expressions are useful when you need a class as a value rather than simply declaring a class in a fixed scope. Common situations include returning a class from a factory function, creating a class conditionally, passing a class to another function, extending a class chosen at runtime, and building mixins.

For a regular class that has a clear, fixed name and is used throughout a module, a class declaration is often easier to read. Choose a class expression when its value-based behavior makes the design simpler or more flexible.

Categorized in:

Javascript, JS Basic,