Classes: The Basics
A class is a blueprint for creating many similar objects without rewriting the same structure over and over.
What Is a Class?
Imagine you run a dog shelter. Every dog has a name, a breed, and can bark. Instead of writing a separate object for every single dog, you write a class once — a blueprint — and then create as many dogs as you need from it.
class Dog {
constructor(name, breed) {
this.name = name;
this.breed = breed;
}
bark() {
return `${this.name} says woof!`;
}
}
const rex = new Dog("Rex", "Labrador");
const bella = new Dog("Bella", "Poodle");
rex.bark(); // "Rex says woof!"
bella.bark(); // "Bella says woof!"
class Dog { ... }— defines the blueprint. The name is always capitalized by convention.constructor(name, breed)— a special setup method. It runs automatically every time you make a new dog. You pass values in here to customize each dog.this.name = name— saves the passed-in value as a property on the new object.thismeans "the object being created right now."bark()— a method (a function attached to the class). Every dog you create will have it.new Dog("Rex", "Labrador")— creates a real dog object from the blueprint.rexandbellaare completely separate objects.
A class is a cookie cutter. The cutter itself is not a cookie — it's just the shape. Every time you press it into dough, you get a new, separate cookie (an "instance"). Each cookie is the same shape but you can decorate each one differently.
Why Do We Use Classes?
When you need to create many objects that share the same structure and behavior — many users, many products, many game characters — a class lets you define that structure once.
Without a class you would repeat yourself constantly:
// Without a class — lots of repeated code
const dog1 = { name: "Rex", breed: "Labrador", bark() { return "Woof!"; } };
const dog2 = { name: "Bella", breed: "Poodle", bark() { return "Woof!"; } };
const dog3 = { name: "Max", breed: "Beagle", bark() { return "Woof!"; } };
// With a class — write once, use forever
const dog1 = new Dog("Rex", "Labrador");
const dog2 = new Dog("Bella", "Poodle");
const dog3 = new Dog("Max", "Beagle");
The Constructor Method
The constructor is a special method inside a class that runs automatically when you use new. Its job is to set up the new object with starting values.
class Person {
constructor(name, age) {
this.name = name; // set the "name" property
this.age = age; // set the "age" property
}
}
const alice = new Person("Alice", 30);
alice.name; // "Alice"
alice.age; // 30
- Every class can have one constructor at most.
- If you don't write a constructor, JavaScript quietly adds an empty one for you — so the class still works.
- Parameters in the constructor (like
name,age) are just regular function parameters — you pass values when you callnew.
If your class doesn't need any setup values, you can skip the constructor entirely. JavaScript will create the object just fine without it.
class Timer {
start() { console.log("Timer started!"); }
}
const t = new Timer(); // no constructor — totally fine
t.start(); // "Timer started!"
Instance Properties
An instance property is a value that belongs to a specific object (instance). Each object you create has its own independent copy of these properties.
class Car {
constructor(make, model, year) {
this.make = make; // instance property
this.model = model; // instance property
this.year = year; // instance property
this.speed = 0; // default value — every new car starts at 0 speed
}
}
const car1 = new Car("Toyota", "Corolla", 2020);
const car2 = new Car("Honda", "Civic", 2022);
car1.make; // "Toyota" — car1's own data
car2.make; // "Honda" — car2's own data, separate from car1
car1.speed = 60; // changing car1's speed...
car2.speed; // still 0 — car2 is not affected
Each object created from the class is completely independent. Changing a property on one object does not affect any other.
Public Class Fields
There is a newer, cleaner way to declare properties: write them directly in the class body, before the constructor. These are called public class fields.
This is useful when a property always starts with the same default value for every object.
class Player {
// Class fields — declared directly in the class body
name = "Unknown"; // default name
score = 0; // every player starts at 0
lives = 3; // every player starts with 3 lives
constructor(name) {
this.name = name; // overwrite the default with the real name
}
addScore(points) {
this.score += points;
}
}
const p1 = new Player("Alice");
const p2 = new Player("Bob");
p1.addScore(10);
p1.score; // 10
p2.score; // still 0 — completely separate
p1.lives; // 3 — came from the class field default
score = 0— every new object automatically getsscoreset to0, before the constructor even runs- You can still override a field in the constructor (like
this.name = name) - Class fields make your code easier to read — you can see all properties at a glance at the top of the class
- Each instance still gets its own separate copy of every field
| Class field | Constructor property | |
|---|---|---|
| Where written | Top of class body | Inside constructor() |
| Good for | Fixed default values | Values passed in from outside |
| Example | score = 0; | this.name = name; |
| Each instance has its own? | Yes | Yes |
You will often use both together: class fields for defaults, constructor for values the caller provides.
Adding Methods
A method is a function you define inside a class. Every object created from the class automatically gets access to all its methods. You define methods just by writing the function name — no function keyword needed inside a class.
class BankAccount {
balance = 0; // class field — every account starts at 0
constructor(owner) {
this.owner = owner;
}
deposit(amount) {
this.balance += amount;
return `Deposited $${amount}. New balance: $${this.balance}`;
}
withdraw(amount) {
if (amount > this.balance) {
return "Not enough money!";
}
this.balance -= amount;
return `Withdrew $${amount}. Remaining: $${this.balance}`;
}
getBalance() {
return `${this.owner}'s balance: $${this.balance}`;
}
}
const acc = new BankAccount("Alice");
acc.deposit(200); // "Deposited $200. New balance: $200"
acc.withdraw(50); // "Withdrew $50. Remaining: $150"
acc.withdraw(500); // "Not enough money!"
acc.getBalance(); // "Alice's balance: $150"
- Methods are shared — all objects from the same class use the same method definition (it lives on the class's prototype, not copied into each object)
- Inside a method,
thisalways refers to the specific object the method was called on - Methods can read and change the object's own properties using
this.propertyName
What Does new Actually Do?
When you write new Dog("Rex", "Labrador"), JavaScript does four things automatically, in order:
// When you write this:
const rex = new Dog("Rex", "Labrador");
// JavaScript does all of this behind the scenes:
// 1. Creates a brand-new empty object: {}
// 2. Links it to Dog's prototype (so it can use Dog's methods)
// 3. Runs the constructor — "this" inside refers to that new object
// 4. Returns the new object automatically
- Step 1 — A fresh empty object is created
- Step 2 — The object is connected to the class (so it can use the class's methods)
- Step 3 — The constructor runs, filling in the properties via
this - Step 4 — That filled-in object is returned and stored in your variable (
rex)
new when creating a class objectCalling a class without new throws a TypeError. Classes are not regular functions — they require new.
Dog("Rex", "Labrador"); // ❌ TypeError: Cannot call a class as a function
new Dog("Rex", "Labrador"); // ✅ correct
Class Expressions
There are two ways to write a class. So far you have seen a class declaration. The other way is a class expression — you store the class in a variable, just like you can store a function in a variable.
// Class declaration (what you've seen so far)
class Dog {
constructor(name) { this.name = name; }
bark() { return "Woof!"; }
}
// Class expression (stored in a variable)
const Dog = class {
constructor(name) { this.name = name; }
bark() { return "Woof!"; }
};
// Both work the same way:
const rex = new Dog("Rex");
rex.bark(); // "Woof!"
// Class expression can also have a name (rarely used)
const Cat = class MyCat {
meow() { return "Meow!"; }
};
const kitty = new Cat(); // use the variable name to create instances
kitty.meow(); // "Meow!"
- Class declarations and class expressions work the same way — the inside code is identical
- Class declarations are more common and easier to read for beginners — use those most of the time
- Class expressions are useful when you want to pass a class as an argument or create it conditionally
- Unlike function declarations, class declarations are NOT hoisted — you cannot use a class before the line where it is defined
// ❌ This throws a ReferenceError
const rex = new Dog("Rex"); // used before it is defined
class Dog { ... }
// ✅ This works — define the class first
class Dog { ... }
const rex = new Dog("Rex");
Checking an Object's Class — instanceof
instanceof lets you ask: "Was this object made from that class?" It returns true or false.
class Dog { }
class Cat { }
const rex = new Dog();
const luna = new Cat();
rex instanceof Dog; // true — rex was made with new Dog()
rex instanceof Cat; // false — rex is not a Cat
luna instanceof Cat; // true
luna instanceof Dog; // false
You can also find the class name as a string using .constructor.name:
class Dog { }
const rex = new Dog();
rex.constructor.name; // "Dog" — the name of the class that created rex
obj instanceof ClassName— returnstrueifobjwas created fromClassName- Useful for checking what kind of object you have before doing something with it
obj.constructor.name— gives you the class name as a string (handy for debugging)
function makeNoise(animal) {
if (animal instanceof Dog) {
console.log("Woof!");
} else if (animal instanceof Cat) {
console.log("Meow!");
} else {
console.log("...");
}
}
A Quick Look at What's Coming
Classes have three more big features, each with its own dedicated lesson. Here is a one-line taste of each so you know what to expect:
Inheritance — extends and super
One class can inherit everything from another class, so you can build specialized versions without rewriting shared code.
class Puppy extends Dog { // Puppy gets everything Dog has
constructor(name, breed, toy) {
super(name, breed); // run Dog's constructor first
this.toy = toy;
}
}
→ Full details in the Inheritance & The super Keyword lesson.
Static Methods & Properties
Some methods and properties belong to the class itself, not to any individual object. You call them on the class name directly.
class MathHelper {
static square(n) { return n * n; }
}
MathHelper.square(5); // 25 — called on the class, not an instance
→ Full details in the Static Properties & Methods lesson.
Getters, Setters & Private Fields
Getters and setters let you run custom code when a property is read or written. Private fields (starting with #) are fully hidden from outside the class.
class Circle {
#radius; // private — only accessible inside this class
constructor(r) { this.#radius = r; }
get area() { return Math.PI * this.#radius ** 2; }
}
→ Full details in the Getters, Setters & Private Fields lesson.
Common Mistakes
- Forgetting
new:Dog("Rex")throws a TypeError. Always writenew Dog("Rex"). - Forgetting
this.inside the constructor: Writingname = name(nothis) does nothing useful —this.name = nameis what saves the value on the object. - Adding a comma between methods: Unlike object literals, methods inside a class do not need commas between them.
- Using the class before defining it: Classes are not hoisted — define the class before you use it.
- Two constructors: A class can only have one
constructor. Adding a second one throws a SyntaxError.
// ❌ Common beginner mistakes
class Dog {
constructor(name) {
name = name; // ❌ forgot "this." — property is never set
}
bark() { return "Woof!"; }, // ❌ no comma between methods in a class
sit() { return "Sitting."; }
}
// ✅ Correct version
class Dog {
constructor(name) {
this.name = name; // ✅ this. is required
}
bark() { return "Woof!"; } // ✅ no comma
sit() { return "Sitting."; }
}
Best Practices
- Always capitalize class names (
Dog, notdog) — this is the universal convention in JavaScript. - Use classes when you need multiple objects with shared structure. For a single one-off object, a plain object literal (
{ name: "Rex" }) is simpler. - Keep the constructor focused on setting up properties. Put real logic inside methods.
- Use class fields for properties that always start with the same default value — it makes the class easier to read at a glance.
- Keep your class focused on one job. A
Dogclass should know dog things. Don't add payment logic to it.
Performance Notes
Classes are essentially a cleaner syntax on top of JavaScript's existing prototype system (covered in the Prototypes lesson). They perform the same as hand-written prototype code. The benefit of classes is readability and structure, not raw speed.
Methods defined in a class are stored once on the class prototype and shared between all instances — you are not creating a new copy of every method for every object, which is very efficient.
Browser Compatibility
The class keyword, constructor, and instance methods have been supported in all major browsers since ES6 (2015). Public class fields (score = 0 written in the class body) were added in ES2022 and are now supported in all modern browsers.
Interview Questions
What is the difference between a class and an instance?
A class is the blueprint — the definition. An instance is an actual object created from that blueprint using new. Each instance has its own independent copy of the properties, but shares the methods defined on the class.
What does the constructor method do?
It is a special method that runs automatically when you use new to create an object from a class. Its job is to set up the starting properties of the new object. A class can have at most one constructor.
What is the difference between a class field and a constructor property?
A class field (e.g. score = 0) is declared in the class body and is great for fixed default values. A constructor property (e.g. this.name = name inside the constructor) is for values that change based on what is passed in when the object is created. You often use both together.
What does instanceof check?
It checks whether an object was created from a specific class and returns true or false. For example, rex instanceof Dog is true if rex was created with new Dog().
✏️ Exercise
Create a Rectangle class with class fields width = 0 and height = 0, a constructor that takes width and height, and a method area() that returns width × height. Create two rectangles and log their areas.
🧠 Quiz
1. What keyword creates a new object from a class?
new — for example new Dog("Rex").
2. Inside a constructor, what does this refer to?
The brand-new object being created right now. Every property you set with this.propertyName = value goes onto that new object.
3. Do you need a comma between methods in a class?
No. Unlike in an object literal, methods inside a class body do not use commas between them.
4. What is a public class field?
A property declared directly in the class body (outside the constructor), like score = 0. Every new instance gets that default value automatically.
🚀 Mini Challenge
Build a Counter class with a class field count = 0. Add three methods: increment() (adds 1), decrement() (subtracts 1, but never below 0), and reset() (sets count back to 0). Then create two separate counters and prove they track their counts independently.
Summary
- A class is a blueprint for creating many similar objects.
- The constructor runs automatically when you use
new— it sets up the object's starting properties. - Instance properties (set with
this.prop = value) belong to each individual object and are independent of each other. - Public class fields (
score = 0in the class body) are a clean way to declare default property values. - Methods are functions inside the class — shared by all instances.
newcreates an object, links it to the class, runs the constructor, and returns the result.- Class expressions store a class in a variable — useful but less common than class declarations.
instanceofchecks whether an object was made from a specific class.- Classes are not hoisted — always define them before you use them.
Related Topics
MDN reference: developer.mozilla.org → JavaScript → Classes