Skip to main content

A class as an expression const A = class {}

Yes, a class in JavaScript is an expression, so const A = class {} is perfectly legal and creates the same class as an ordinary declaration. The only differences are how the class enters scope and whether it has a name visible from the outside.

Theory

TL;DR

  • A class can be declared with a declaration, class User {}, or with an expression, const User = class {}.
  • A class expression can be anonymous or named; the name of a named one is visible only inside the class body.
  • Class expressions are what you need for dynamic class selection, class factories and classes local to a function.
  • Neither a declaration nor an expression can be used before its declaration: both sit in the temporal dead zone.
  • A class can be created and used inline right away: new (class { ... })().

Quick example

javascript
// Class declaration class UserA { greet() { console.log("Hello!"); } } // Class expression const UserB = class { greet() { console.log("Hello!"); } }; new UserA().greet(); // Hello! new UserB().greet(); // Hello!

Both forms create a class, the difference is only in where and how it is declared.

Anonymous and named expressions

A class expression can be anonymous or named.

Anonymous:

javascript
const User = class { greet() { console.log("Hello!"); } };

Named:

javascript
const User = class MyUser { greet() { console.log(MyUser.name); // "MyUser" } }; const u = new User(); u.greet(); // MyUser

The name MyUser is visible only inside the class itself, from the outside only the variable User is available.

javascript
console.log(typeof MyUser); // ReferenceError

This mirrors named function expressions: the inner name is handy for recursive references and readable stack traces, but it does not create an outer variable.

Where this is useful

1. When the class has to be created dynamically. For example, depending on a condition:

javascript
const Animal = condition ? class Dog { bark() { console.log("Woof!"); } } : class Cat { meow() { console.log("Meow!"); } }; const pet = new Animal();

2. When a class has to be returned from a function (a class factory).

javascript
function createModel(name) { return class { constructor(id) { this.id = id; this.modelName = name; } }; } const UserModel = createModel("User"); const user = new UserModel(1); console.log(user.modelName); // "User"

Very convenient for building models, entities, adapters and so on dynamically. The same trick is the basis of mixins: a function takes a base class and returns class extends Base { ... }.

3. When the class should be local, inside a function.

javascript
function makeCounter() { return class { #count = 0; inc() { this.#count++; return this.#count; } }; } const Counter = makeCounter(); const c = new Counter(); console.log(c.inc()); // 1

The class lives only inside the function and does not pollute the global scope.

Hoisting behaviour

A class declaration is not hoisted the way a function is: the class name is reserved, but until the declaration line it stays in the temporal dead zone. A class expression behaves like any const variable, that is, it is available only after the declaration.

javascript
new User(); // ReferenceError: Cannot access 'User' before initialization const User = class {};

So, as far as hoisting goes, both forms are the same in practice: you cannot use a class before it is declared.

A class as an inline value

Since a class is an expression, it can be created and applied straight away without ever being named:

javascript
console.log( new (class { sayHi() { console.log("Hello!"); } })() ); // an instance of a temporary class

This trick is often used in tests and demos, so that no separate class name has to be introduced.

Summary table

TypeExampleWhere the name is availableHoisted?
Class Declarationclass User {}Everywhere after the declarationNo
Anonymous Class Expressionconst A = class {}There is no nameNo
Named Class Expressionconst A = class MyA {}Only inside the classNo

In short: a class can be used as an expression, which is convenient for dynamic, local and temporary classes, and the class name in that form can be local or absent entirely.

Common mistakes

  • Thinking the name of a named class expression is visible outside. const A = class MyA {} does not create a MyA variable in the outer scope.
  • Using the class before its declaration line. That is a ReferenceError because of the temporal dead zone, for declarations too.
  • Forgetting the semicolon after the expression. const A = class {} ends with an expression, so a missing ; can make the next line continue it unexpectedly.
  • Getting A.name wrong for an anonymous class. In const A = class {} the engine infers the name from the variable, so A.name gives "A", not an empty string.
  • Creating classes in a hot loop. A class factory builds a new class with a new prototype on every call, so instances from different calls fail instanceof against each other.
  • Expecting a class expression to escape strict mode. A class body is always strict, whatever the declaration form.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.