Classes and Instances
What are classes and instances?
A class is a blueprint for creating objects. An instance is an object created from that class.
Classes let you define one reusable shape, then create many objects that follow that shape.
class Car {
constructor(make) {
this.make = make;
}
}
const myCar = new Car("Toyota");
console.log(myCar.make); // "Toyota"
Car is the class. myCar is an instance.
Why this matters
Classes are useful when you need many objects with the same shape and behavior. Instead of manually creating similar objects over and over, you define the structure once in a class and create instances with new.
Creating instances with new
Use new ClassName() to create an instance:
class Car {
constructor(make) {
this.make = make;
}
}
const car1 = new Car("Toyota");
const car2 = new Car("Honda");
console.log(car1 === car2); // false
console.log(car1.make); // "Toyota"
console.log(car2.make); // "Honda"
Each call to new Car() creates a fresh object.
What happens:
- JavaScript creates a new empty object.
- The class constructor runs.
thispoints to the new object.- The finished object is assigned to the variable.
The constructor
The constructor method is a special method that runs automatically when you create a new instance. Use it to set up instance data.
class Car {
constructor(make, model, color) {
this.make = make;
this.model = model;
this.color = color;
}
}
const car = new Car("Toyota", "Camry", "Blue");
console.log(car.make); // "Toyota"
console.log(car.model); // "Camry"
console.log(car.color); // "Blue"
Arguments passed to new Car(...) become arguments to constructor.
The constructor should usually set up the object's starting state. Keep it predictable and avoid doing unrelated work there.
Call a class with new. Calling Car("Toyota", "Camry", "Blue") without new causes an error.
Instance properties
Instance properties store data on each individual object:
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
this.mileage = 0;
}
}
const car1 = new Car("Toyota", "Camry");
const car2 = new Car("Honda", "Civic");
car1.mileage = 100;
console.log(car1.mileage); // 100
console.log(car2.mileage); // 0
Changing one instance does not change another instance.
This is the main mental model for instances: each instance has its own property values.
Adding properties manually
JavaScript objects are flexible, so you can add properties after creation:
class Car {}
const car = new Car();
car.make = "Toyota";
car.model = "Camry";
console.log(car.make); // "Toyota"
This works, but it is easy to forget a property or create inconsistent objects. Prefer setting expected properties in the constructor.
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
}
}
const car = new Car("Toyota", "Camry");
console.log(car.model); // "Camry"
Rule of thumb: if every instance should have the property, initialize it in the constructor.
Missing properties
If you read a property that does not exist, JavaScript returns undefined:
class Car {
constructor(make) {
this.make = make;
}
}
const car = new Car("Toyota");
console.log(car.year); // undefined
Use in or Object.hasOwn() when you need to check for a property:
if ("year" in car) {
console.log(car.year);
} else {
console.log("No year set");
}
Use this kind of check when missing data is expected. If the property should always exist, it is usually better to initialize it in the constructor.
Instance methods
Methods are functions defined inside a class. They usually work with instance data through this.
class Car {
constructor(make, model, color) {
this.make = make;
this.model = model;
this.color = color;
this.mileage = 0;
}
drive(miles) {
this.mileage += miles;
return this.mileage;
}
getInfo() {
return `${this.color} ${this.make} ${this.model}`;
}
}
const car = new Car("Toyota", "Camry", "Blue");
console.log(car.drive(100)); // 100
console.log(car.getInfo()); // "Blue Toyota Camry"
Instance methods are shared through the class, but they work with the specific instance that calls them.
The next guide, Methods and this, covers methods and this in more detail.
Class names and file organization
Class names usually use PascalCase, where each word starts with a capital letter:
class UserAccount {}
class ShoppingCart {}
class GamePlayer {}
Use names that describe the kind of object the class creates. UserAccount is clearer than Data or Manager when the class represents a user account.
In larger programs, it is common to put one main class in its own module:
// UserAccount.js
export class UserAccount {
constructor(name) {
this.name = name;
}
}
This keeps the class easy to find and reuse.
Common patterns
Default property values
class Task {
constructor(title) {
this.title = title;
this.isComplete = false;
}
}
const task = new Task("Learn classes");
console.log(task.isComplete); // false
Creating multiple instances
class User {
constructor(name) {
this.name = name;
}
}
const users = [
new User("Alice"),
new User("Bob"),
new User("Charlie"),
];
console.log(users[0].name); // "Alice"
Use this pattern when you need a collection of similar objects.
Checking an instance's class
class User {}
const user = new User();
console.log(user instanceof User); // true
instanceof checks whether an object was created by a class or inherits from it. It is useful for debugging and occasional validation, but most everyday code works better by calling methods or checking the data you actually need.
Common mistakes
Forgetting new
class User {
constructor(name) {
this.name = name;
}
}
// This would cause an error:
// const user = User("Alice");
const user = new User("Alice");
console.log(user.name); // "Alice"
Sharing state accidentally
Be careful with object or array values that are meant to belong to each instance.
const sharedSongs = [];
class Playlist {
constructor(name) {
this.name = name;
this.songs = sharedSongs;
}
}
const roadTrip = new Playlist("Road trip");
const focus = new Playlist("Focus");
roadTrip.songs.push("Song A");
console.log(focus.songs); // ["Song A"]
Both playlists point at the same array. That is usually not what you want.
Create arrays and objects inside the constructor when each instance needs its own copy:
class Playlist {
constructor(name) {
this.name = name;
this.songs = [];
}
addSong(song) {
this.songs.push(song);
}
}
const roadTrip = new Playlist("Road trip");
const focus = new Playlist("Focus");
roadTrip.addSong("Song A");
console.log(roadTrip.songs); // ["Song A"]
console.log(focus.songs); // []
Best practices
- Use classes for repeated shapes: Classes are useful when many objects share the same setup and behavior.
- Initialize expected properties in
constructor: This keeps instances consistent. - Use
thisfor instance data:this.namemeans thenameproperty on the current instance. - Avoid adding random properties later unless the object is intentionally flexible.
- Keep constructors simple: Heavy work usually belongs in methods or helper functions.
- Use clear class names: Class names usually use PascalCase, like
UserAccount.
Summary
Classes are blueprints, and instances are objects created from those blueprints. Use new to create an instance, constructor to initialize instance data, and this to store properties on the current instance. Each instance has its own state, while methods define shared behavior.