Suggest an editImprove this articleRefine the answer for “A class as an expression const A = class {}”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Yes, a class is a full expression: `const A = class {}` creates exactly the same class as `class A {}`, the difference is only in where and how it is declared.** A class expression can be anonymous (`const User = class {}`) or named (`const User = class MyUser {}`), and the name `MyUser` is visible only inside the class body, while from the outside only the variable `User` is available. This form is what you need when a class has to be built dynamically (a ternary choice between two classes), returned from a factory function, or kept local inside a function without polluting the global scope. You cannot use it before its declaration line: a `const` sits in the temporal dead zone. ```javascript function createModel(name) { return class { constructor(id) { this.id = id; this.modelName = name; } }; } const UserModel = createModel("User"); console.log(new UserModel(1).modelName); // "User" ``` **Key point:** yes, `const A = class {}` is perfectly legal, it suits dynamic, local and temporary classes, and the class name there can be local or absent entirely.Shown above the full answer for quick recall.Answer (EN)Image**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 | Type | Example | Where the name is available | Hoisted? | | --- | --- | --- | --- | | **Class Declaration** | `class User {}` | Everywhere after the declaration | No | | **Anonymous Class Expression** | `const A = class {}` | There is no name | No | | **Named Class Expression** | `const A = class MyA {}` | Only inside the class | No | 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.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.