Classes
Learn how to define classes in JavaScript, write constructors and instance methods, create objects with new, and understand that classes are really just syntactic sugar over prototypes.
Reading Time
20 min
Lesson
Lesson 39 of 48
What is a Class?
A class is a template for creating objects that share the same shape — the same properties and the same methods. Instead of writing out an object literal from scratch every time you need a new user, product, or task, you define a class once, describing what every instance should have, and then create as many instances as you need with the new keyword. Classes were introduced in ES6 as a cleaner, more familiar syntax for something JavaScript could already do with functions and prototypes — they don't add a new capability to the language, they add a nicer way of expressing an existing one.
Class Declaration Syntax
A class is declared with the class keyword followed by a name, written in PascalCase by convention (capitalized, like User or Product), and a body wrapped in curly braces. Inside that body you can define a constructor, instance methods, and instance properties — notice there are no commas between members, unlike an object literal.
A Minimal Class
Console Output
Click “Run” to see the console output here.
The Constructor Method
The constructor is a special method that runs automatically whenever a new instance is created with new. It's where you typically set up the instance's initial properties, usually based on arguments passed in when the object is created. A class can have at most one constructor — defining a second one is a syntax error. If you omit the constructor entirely, JavaScript provides an empty default one for you.
Constructor Receiving Arguments
Console Output
Click “Run” to see the console output here.
Instance Methods
Any function defined inside the class body (other than the constructor) becomes an instance method — a function every object created from the class can call. Instance methods are defined once on the class and shared by all instances, rather than being recreated for every single object, which makes them memory-efficient compared to assigning a function directly inside the constructor.
Multiple Instance Methods
Console Output
Click “Run” to see the console output here.
Instance Properties
Instance properties are the data that belongs to each individual object — things like name, email, or price above. They're usually assigned inside the constructor using this, but modern JavaScript also lets you declare them directly in the class body as class fields, with or without a default value, which get set on every instance before the constructor body runs.
Class Fields as an Alternative to Constructor Assignment
Console Output
Click “Run” to see the console output here.
Creating Instances with new
Calling a class with the new keyword does several things at once: it creates a brand-new empty object, sets that object's internal prototype to the class's prototype, runs the constructor with this bound to the new object, and returns the object (unless the constructor explicitly returns a different object). Forgetting new is a common mistake — calling User(...) without new throws an error, because classes cannot be called as plain functions.
What Happens Without new
Console Output
Click “Run” to see the console output here.
Classes are Syntactic Sugar Over Prototypes
Under the hood, a class is still using JavaScript's original prototype-based inheritance model — class methods are placed on the class's prototype object, exactly the way they would be if you'd built them manually. Writing class User { ... } and writing a constructor function with methods attached to User.prototype produce objects that behave almost identically. The class syntax doesn't change what's possible, it just makes the intent clearer and catches a few mistakes (like calling without new) that plain functions wouldn't.
A Class vs. the Equivalent Constructor Function
Console Output
Click “Run” to see the console output here.
Class Syntax vs. Constructor Function + Prototype
| Aspect | Class | Constructor Function |
|---|---|---|
| Method storage | Automatically placed on Class.prototype | Must be manually assigned to Fn.prototype |
| Calling without new | Throws a TypeError | Silently runs with this as the global object (sloppy mode) |
| Hoisting | Not initialized until the class definition runs | Fully hoisted, like any function declaration |
| Strict mode | Class bodies are always strict mode | Depends on surrounding code |
Classes Are Not Hoisted the Same Way
Function declarations are hoisted and can be called before their definition appears in the file. Classes are hoisted too, but they land in a 'temporal dead zone' — trying to use a class before its declaration throws a ReferenceError instead of quietly working. Always declare a class before you construct instances of it.
Keep Constructors Focused on Setup
A good habit is to keep the constructor limited to assigning initial properties, and put any real logic into instance methods instead. If a constructor starts making network calls or running heavy computations, it becomes hard to control when that work actually happens, since it fires the instant new is called.