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. this means "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. rex and bella are completely separate objects.
🍪 Real-life analogy

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 call new.
💡 No constructor needed?

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 gets score set to 0, 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 fields vs constructor properties
Class fieldConstructor property
Where writtenTop of class bodyInside constructor()
Good forFixed default valuesValues passed in from outside
Examplescore = 0;this.name = name;
Each instance has its own?YesYes

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, this always 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)
⚠ Always use new when creating a class object

Calling 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
⚠ Classes are not hoisted like functions
// ❌ 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 — returns true if obj was created from ClassName
  • 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)
💡 Practical example
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

⚠ Watch out for
  • Forgetting new: Dog("Rex") throws a TypeError. Always write new Dog("Rex").
  • Forgetting this. inside the constructor: Writing name = name (no this) does nothing useful — this.name = name is 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, not dog) — 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 Dog class 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 = 0 in the class body) are a clean way to declare default property values.
  • Methods are functions inside the class — shared by all instances.
  • new creates 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.
  • instanceof checks 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