JavaScript Classes Explained: Complete Tutorial
Classes are templates for creating objects with shared methods and data. Learn how to define a class, write a constructor, add methods, and create instances in JavaScript.
A JavaScript class is a blueprint for creating objects that share the same shape and behavior. Instead of writing a separate object literal for every user, product, or component, you define a class once and use new to stamp out as many instances as you need.
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
greet() {
return `Hello, I am ${this.name}`;
}
}
const alice = new User("Alice", "alice@example.com");
console.log(alice.greet()); // "Hello, I am Alice"The class block defines the template, and new User(...) creates an instance from it. Each instance gets its own name and email, but every instance shares a single copy of the greet method. That is the core idea behind classes: define once, share behavior, own unique data.
The Constructor
The constructor method runs automatically when you call new on a class. Its job is to set up the instance with its own properties, using whatever parameter names make sense for that class.
class Book {
constructor(title, author, pages) {
this.title = title;
this.author = author;
this.pages = pages;
}
}
const book = new Book("Eloquent JavaScript", "Marijn Haverbeke", 472);
console.log(book.title); // "Eloquent JavaScript"
console.log(book.pages); // 472Each argument passed to the constructor lands inside this, which refers to the new object being built. Every property assigned to this becomes an own property of that specific instance. If you skip the constructor entirely, JavaScript supplies an empty one for you. A class can only have one constructor; adding a second throws a syntax error.
Instance Methods
Methods written inside the class body, outside the constructor, become shared methods on the prototype. Every instance uses the same function in memory instead of storing its own copy.
class Counter {
constructor(start = 0) {
this.value = start;
}
increment() {
this.value += 1;
return this.value;
}
}
const counter = new Counter(5);
console.log(counter.increment()); // 6
console.log(counter.increment()); // 7The value property is separate for each counter instance, but the increment method itself is shared across every instance. Calling counter.increment() finds that shared method and runs it with the counter object as its context.
Getters and Setters
A getter looks like a plain property read but runs a function behind the scenes. A setter intercepts an assignment the same way. Use them for computed properties or validation without forcing callers to write a method call.
class Temperature {
constructor(celsius) {
this._celsius = celsius;
}
get fahrenheit() {
return this._celsius * 9 / 5 + 32;
}
set fahrenheit(value) {
this._celsius = (value - 32) * 5 / 9;
}
}
const temp = new Temperature(25);
console.log(temp.fahrenheit); // 77Reading temp.fahrenheit calls the getter, and writing to it calls the setter. The leading underscore on the stored field is only a naming convention that signals "internal"; it is not truly private. For real privacy, use private class fields.
Class Fields
Class fields let you declare instance properties directly in the class body, without writing them inside the constructor. This is cleaner when the starting value does not depend on constructor arguments.
class TodoItem {
completed = false;
constructor(text) {
this.text = text;
}
toggle() {
this.completed = !this.completed;
}
}
const todo = new TodoItem("Buy groceries");
console.log(todo.completed); // false
todo.toggle();
console.log(todo.completed); // trueFields declared this way are set before the constructor body runs, and they become own properties on every instance. A field without an initial value simply defaults to undefined.
Static Methods and Fields
A static member belongs to the class itself, not to any instance. Static methods work well as utility functions, and static fields work well as shared constants or configuration.
class MathUtils {
static PI = 3.14159;
static square(x) {
return x * x;
}
}
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.square(5)); // 25
const utils = new MathUtils();
// utils.square(5); throws TypeError: not a functionStatic members live on the class function itself, so they are never reachable from an instance. That final commented-out line would throw at runtime if you actually ran it.
How Classes Work Under the Hood
Classes are not a new kind of thing in JavaScript. They are a cleaner way to write the constructor-function and prototype-method pattern that existed long before the class keyword. Understanding this connection helps when you read older code or debug inheritance.
Writing a class makes JavaScript create a constructor function and a prototype object behind the scenes. Calling new User("Alice") creates an object whose internal prototype link points to that shared object. The greet method lives there, so every instance finds it by following the link instead of storing its own copy.
The class syntax is roughly equivalent to a plain constructor function with a method attached to its prototype property afterward. Both forms produce the same result, but the class version is always strict mode and reads more clearly.
When to Use a Class
Classes shine when you need many objects that share behavior:
- Modeling data: a User, Product, Order, or Post class with properties and methods.
- UI components: a Button, Modal, or Accordion class that manages DOM state.
- Services: an HttpClient or Logger class with shared configuration and methods.
- State management: a Store or Observable class that holds state and notifies listeners.
If you only need one plain object with no shared methods, a simple object literal is lighter and often the better choice. Do not reach for a class just to group a few values together.
For a deeper look at inheritance built on classes, see class inheritance.
Rune AI
Key Insights
- A class is a template for creating objects with shared structure and behavior.
- The constructor method runs once per instance and sets up the object's own properties.
- Methods defined in the class body are shared across all instances via the prototype.
- Use get and set for computed property access that looks like a simple property read.
- Static methods and fields belong to the class itself, not to any instance.
Frequently Asked Questions
Are JavaScript classes the same as classes in Java or C++?
Can I use classes in older browsers?
Should I use classes or factory functions?
Conclusion
Classes make object creation predictable and readable. Define your object shape once with a constructor and shared methods, then create as many instances as you need. Start with a simple class, add methods, and use getters for computed properties. When you need private data, reach for private fields, and when you need shared logic, use static methods.
More in this topic
Using Decorators for Logging in JS Architecture
Learn how JavaScript decorators wrap class methods to add logging without touching the original code, including setup with Babel and how execution order works.
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.