Progress pill
Basic JavaScript

Objects and classes

  • What is an object ?
  • Creating an object
  • Classes and constructors
  • Changing the shape of an object
  • Inheritance with extends and super()
  • Instanceof
JavaScript is often called an object-oriented language.
That means it helps you organize your code by grouping values and functions together into objects.

What is an object ?

An object can contain data and functions that operate on that data. When a function is put into an object we say it's a method.
The first object we've seen was the console object. It's an object that contains multiple methods to print thing on the screen and debug our programs.
It can even print itself; you can do
console.log(console)
and it will print a list of the methods that it contains. For example, on my machine it printed
Object [console] { log: [Function: log], warn: [Function: warn], error: [Function: error], dir: [Function: dir], time: [Function: time], timeEnd: [Function: timeEnd], timeLog: [Function: timeLog], trace: [Function: trace], assert: [Function: assert], clear: [Function: clear], count: [Function: count], countReset: [Function: countReset], group: [Function: group], groupEnd: [Function: groupEnd], table: [Function: table], debug: [Function: debug], info: [Function: info], dirxml: [Function: dirxml], groupCollapsed: [Function: groupCollapsed], Console: [Function: Console], profile: [Function: profile], profileEnd: [Function: profileEnd], timeStamp: [Function: timeStamp], context: [Function: context], createTask: [Function: createTask] }
As you can see, it has a lot of methods that you could use to debug!
Javascript provides us with different way to create new objects that can do whatever we want them to do.

Creating an object

The easiest way to create an object is just by grouping data and functions using curly braces {}.
This creates what we call an anonymous object
const cat = { name: "Whiskers", age: 3 }
This creates an object and stores it in a variable called cat.
The object has two properties:
  • name with the value "Whiskers"
  • age with the value 3
Let’s print it:
console.log(cat)
This prints:
{ name: 'Whiskers', age: 3 }
You can get the properties out of the object using a dot, as in objectName.propertyName:
console.log(cat.name) // prints "Whiskers" console.log(cat.age) // prints 3
You can also change a property:
cat.age = 4 console.log(cat.age) // now it prints 4
As you can see, even if an object is defined as const, you can still modify the data it contains.
In the case of objects, const will only stop you from overriding the whole object:
const cat = { name: "Whiskers", age: 3 } cat.age = 5 // this works cat = 5 // this throws an error, you're trying to reassign the whole object
As mentioned before, objects can also hold functions, and when a function is part of an object, we call it a method.
Here’s an example:
const cat = { name: "Whiskers", speak () { console.log("Meow!") } }
This object has:
  • A name property
  • A speak() method
Let’s call the method:
cat.speak()
It prints:
Meow!
Methods can use the data the object contains through the keyword this. this refers to the current object. In this example, it will be used to print the name of the cat:
const cat = { name: "Whiskers", speak () { console.log(`${this.name} says meow!`) } } cat.speak()
This prints:
Whiskers says meow!
The word this means "this object"...in this case, the cat object.
These kinds of objects are great when you just want something quick and simple. But if you need to create many objects with the same structure, there’s a better way, and that’s where classes come in.

Classes and constructors

A class is like a blueprint. It tells JavaScript how to create a certain kind of object.
You define a class using the class keyword, followed by the name of the class, and by a curly braces {} block.
class Dog {}
Classes usually start with an upper case letter, by convention.
You can create a new object of a class using new:
const hachiko = new Dog()
Try to print the object:
class Dog {} const myDog = new Dog() console.log(myDog)
You'll get
Dog {}
As you can see the Dog class is empty, so the myDog object is empty too.
We can define which properties Dog objects should contain by adding a constructor.
A constructor is a special function that runs when you create (or "construct") a new object.
class Dog { constructor() { } }
We want each Dog to have a name, so we add a name parameter to the function:
class Dog { constructor(name) { } }
And then we use this to declare that name is the name of the Dog object we're building
class Dog { constructor(name) { this.name = name }}
Let's try to use it now:
class Dog { constructor(name) { this.name = name } } const myDog = new Dog("hachiko") console.log(myDog)
This prints something like:
Dog { name: 'hachiko' }
As you can see, the constructor method takes the arguments you pass to the class when you do new Dog(), and it uses it to build the object.
Let’s break it down:
  • class Dog defines the Dog class.
  • constructor(name) sets up the object when it’s created.
  • this.name = name stores the value in the new object.
  • new Dog("hachiko") creates a new object from the class, with the name property set to "hachiko".
Now let's add a method to our class:
class Dog { constructor(name) { this.name = name } speak () { console.log(`${this.name} says barf!`) } } const myDog = new Dog("hachiko") myDog.speak()
This will print
hachiko says barf!
If we do the same for two different instances of Dog
class Dog { constructor(name) { this.name = name } speak () { console.log(`${this.name} says barf!`) } } const myDog = new Dog("hachiko") myDog.speak() const yourDog = new Dog("bobby") yourDog.speak()
we get
hachiko says barf! bobby says barf!
The speak() method uses the name property of the Dog it's called on.
This is the main reason classes exist: they allow us to define a set of methods that operate on data, and then create multiple objects that share the same data "shape".
When we call a method on one of these objects, it will operate on the data that specific object holds.

Changing the shape of an object

Objects in JavaScript are flexible. Even after you've created one, you can still add new properties or remove existing ones.
It's allowed, but it's something you should use carefully.
Let’s start with our simple Dog class:
class Dog { constructor(name) { this.name = name } speak() { console.log(`${this.name} says barf!`) } } const myDog = new Dog("Fido")
At this point, myDog only has one property: name. We can still add new properties after it’s created:
myDog.age = 5 console.log(myDog.age) // prints 5
We can also add a new method:
myDog.jump = function () { console.log(`${this.name} jumps!`) } myDog.jump() // Fido jumps!
And we can remove properties too, using the delete keyword.
delete myDog.name console.log(myDog.name) // prints 'undefined'
This works, but here's something important to know: JavaScript engines like the V8 (used in Node.js and in the Chrome browser) run faster when your objects always maintain the same properties. If you add or remove properties after the object is created, it can slow things down.
In small programs, this doesn’t matter much. But in bigger projects (like games), it’s better to list all the properties in the constructor from the start, even if you don’t use them right away. This keeps the object shape stable and helps your code run faster.
For example, instead of this:
class Dog { constructor(name) { this.name = name } } const dog = new Dog("Rex") dog.age = 4 dog.breed = "Labrador"
You could do
class Dog { constructor(name, age, breed) { this.name = name this.age = age this.breed = breed } } const dog = new Dog("Rex", 4, "Labrador")
Both versions work, but the second one is better for performance. You're telling the engine up front which properties each object will have, and it can optimize accordingly.
JavaScript lets you reshape objects freely, but when using classes, it’s best to plan your object’s shape ahead of time.

Inheritance with extends and super()

Sometimes you want to create a class that’s almost the same as another class, but with a few extra features.
Instead of modifying the shape of objects (which as mentioned before it's not optimal for performance), or having to rewrite a new class from scratch, JavaScript lets you use something called inheritance.
Inheritance means one class can extend another. The new class gets all the properties and methods of the old one, and you can add more or change what you need.
Let’s say we have a base class called Vehicle:
class Vehicle { constructor(brand) { this.brand = brand } start() { console.log(`${this.brand} vehicle is starting...`) } }
Now we want to make a Car class. A car is a kind of vehicle, but we might want it to have some extra features or a different message when it starts. Instead of rewriting everything, we can use extends:
class Car extends Vehicle { start() { console.log(`${this.brand} car is ready to drive!`) } }
The Car class now inherits everything from Vehicle. It gets the brand property, and we’ve replaced the start() method with our own version.
Let’s try it out:
const myCar = new Car("Toyota") myCar.start()
This prints:
Toyota car is ready to drive!
Even though Car doesn’t have its own constructor, it still uses the one from Vehicle. But if we want to write a custom constructor in Car, we can, we just need to include a call to the constructor of its parent using super().
Here’s how:
class Vehicle { constructor(brand) { this.brand = brand } start() { console.log(`${this.brand} vehicle is starting...`) } } class Car extends Vehicle { constructor(brand, model) { super(brand) // call the parent constructor and passes the brand argument to it this.model = model } start() { console.log(`${this.brand} ${this.model} is ready to drive!`) } } const myCar = new Car("Toyota", "Corolla") myCar.start()
This prints:
Toyota Corolla is ready to drive!
So to summarize
  • extends means one class is based on another.
  • super() is used to call the constructor of the class you're extending. The new class gets all the properties and methods of the original class.
  • You can override methods (like start()) to make them do something different.
This is helpful when you have several things that are similar (like cars, trucks, and bikes) and you want them to share code but still behave in their own way.

instanceof

The instanceof keyword checks if an object was created from a certain class.
Let’s say we have a class called User:
class User { constructor(username) { this.username = username } } const regularUser = new User("julia123") console.log(regularUser instanceof User)
This prints:
true
Confirming that regularUser is a User. That’s because regularUser was created using the User class.
It also works with inherited classes. For example, here’s an Admin class that extends User:
class Admin extends User {} const ourAdmin = new Admin("admin42") console.log(ourAdmin instanceof Admin) // true console.log(ourAdmin instanceof User) // true
Both lines return true. That’s because Admin is a subclass of User, therefore ourAdmin is both an Admin and a User