JavaScript Essentials: Deep Dive into Objects and Prototypes

JavaScript Essentials: Deep Dive into Objects and Prototypes

Concepts

  1. What is an object?

  2. Why do we use objects?

  3. How to create objects?

  4. How to add properties and methods to objects?

  5. How to access to properties and methods of objects?

  6. How to inherit objects (prototypes)?

What is an object? Why do we use Objects?

An object is one of the data types of javascript. Unlike primitive data types (like string, number, boolean, etc.), objects can store multiple types of data within them. You can think of real-life objects to understand JavaScript objects.

For instance, think about your computer. A computer has a model, screen size, number of buttons, etc. These are called properties of a computer object. But a computer also has some functions like when you press the on/off button it opens or closes the computer or when you press any of the keys it prints the key on the screen. And these are the methods of the computer object.

What we can understand from our example is javascript objects can store properties and methods under one object instead of storing these properties (variables) separately one by one as a global variable.

// Variables
const model = “Lenovo ThinkPad E14 Gen 2”;
const screenSize = “14 inches”;
const isOpen = true

// Functions
function openClose(isOpen) {
    isOpen = !isOpen;
}

function printKey(key) {
    console.log(key);
}

How to create an Object? How to add properties and methods to an object?

There are 3 ways to create an object:

  1. Object initializers (object literals)

  2. Constructor functions

  3. Object.create() method

Object initializers (object literals)

Objects are key and value properties in curly braces { key1: value1 }. So you can create an object with this syntax. But we mostly need to assign it to a name (or variable) to be able to access the object. Let’s create a computer object with a few properties and methods:

// Creating a computer object

const computer = {
  model: "Lenovo ThinkPad E14 Gen 2",
  screenSize: "14 inches",
  isOpen: true,

  openClose: function () {
    isOpen = !isOpen;
  },
  printKey: function (key) {
    console.log(key);
  }
};

As you can see we create an object and add some variables (properties). The first part of the properties are called ‘keys’ and the values after the punctuation mark (:) are called ‘values’. We create properties and methods in an object like so, and separate them with a comma (,).

Constructor functions

Constructor functions are created like normal functions but the function's name must start with a capital letter. Let’s look at the example of how we can create computer objects with constructor functions:

// Creating constructor function
function Computer(model, screenSize, isOpen) {
  this.model = model;
  this.screenSize = screenSize;
  this.isOpen = isOpen;

  this.openClose = function () {
    this.isOpen = !this.isOpen;
  };

  this.printKey = function (key) {
    console.log(key);
  };
}

// Creating an object instance of the Computer constructor function
const computerA = new Computer("Lenovo ThinkPad E14 Gen 2", "14 inches", false);

As you can see we created the constructor function like a normal function. But it has some additional keywords (like ‘this’). The ‘this’ keyword refers to object created with this constructor function.

This constructor function is like a template that enables us to create multiple objects with the same properties and methods. It’s a best practice to create multiple objects with similar properties and methods. It makes our code more DRY.

After we created our constructor function, we created an object with the keyword ‘new’. This keyword made our constructor function differ from the normal functions. We created a computerA object with the Computer constructor function.

This method of creating object will enable us to create multiple objects that have the same properties and methods. So we can create another Computer object with :

const computerB = new Computer("Macbook Pro", "24 inches", true);

Object.create()

We created multiple objects with the same properties and methods using constructor functions. With the Object.create() function we can also create multiple objects like so.

// first create an object with object literals
const computerA = {
  model: "Lenovo ThinkPad E14 Gen 2",
  screenSize: "14 inches",
  isOpen: true,

  openClose: function () {
    isOpen = !isOpen;
  },
  printKey: function (key) {
    console.log(key);
  }
};

// Then create an instance object using the object.create method

const computerB = Object.create(computerA);

After we create our object computerA with object literals, then we create another object with Object.create(computerA) command. Now computerB also has the same properties and methods for itself. However, each of the objects is unique to its properties and methods. So if you change model of the computerA, the computerB does not change its model, too.

How to access the properties and methods of an object?

We created our object. Now how can we access our computer object's properties and methods? It is very simple. We use dot notation to access any of the properties and methods. Let’s console.log our computerA and computerB object models and on/off the computer's status by calling their openClose methods:

// Print the models of the objects
console.log(computerA.model); // "Lenovo ThinkPad E14 Gen 2"
console.log(computerB.model); // "Macbook Pro"

// Print the on/off status of the objects
console.log(computerA.isOpen); // false
console.log(computerB.isOpen); // true

// Change the on/off status of the objects
computerA.openClose();
computerB.openClose();

// Print the on/off status of the objects
console.log(computerA.isOpen); // true
console.log(computerB.isOpen); // false

As you can see, each object has its own values.

Inheriting Objects (prototypes)

Every JavaScript object we create has a [[Prototype]] property. Have you noticed?

As you can see under the name property it also has a property called [[Prototype]]. This property is automatically created when you create an object. Its value is also an object and we can add properties and methods to it.

Let’s see what is inside the [[Prototype]] property of our person object by default:

So these are the properties of the Object.prototype. Our created objects inherit these properties from the Object.prototype to be able to use these methods on every object we create.

In JavaScript, prototypes are used to inherit objects. The example we gave in the up is the default inheritance. We can also inherit between our objects, too. There are a number of ways to inherit objects so we will explain when to use them.

Inheriting from object-to-object

  1. Object.setPrototypeOf

In order to inherit an object that is created using object literals, we have 2 options but first, let’s create an object that we will inherit from;

So we created a human object with 2 properties and 2 methods. Then we decided to create a me object that has different property values but we also want to have talk and eat methods the same way.

We said we needed to use prototypes of objects to inherit our objects. So we will add the human object to me object’s [[Prototype]]. In order to do that we can use Object.setPrototypeOf function.

That function takes 2 parameters:

  1. the object that we will set the prototype of

  2. the object that we will inherit from

Let’s look at the prototype of me object with Object.getPrototypeOf function:

Here are our human object’s properties so we can access these properties within the me object.

  1. Object.create

We can also inherit human object to me object while we create me object with Object.create function. This function takes a parameter that is the object that will be the prototype of me.

Object.create function assign the me object’s prototype to human so we inherit the human object and can be use it’s properties and methods.

Creating inherited objects with Constructor functions

If you want your created objects inherited, you can use inheritance in constructor functions. Let’s create a Human constructor function to create new human objects.

Here we created our Human constructor function. It has 2 properties called name and sayMyName method. Then we’ve created a person instance with the new keyword. Our person now has their own copy of the name and sayMyName function. But here’s the problem; let’s say we have multiple objects that were created with the Human constructor function, and we wanted to change our sayMyName function or add new functions to Human objects at runtime. Because our created objects have copies of the Human constructor function’s properties, we need to update each function one by one for every object we create.

In order to solve this problem, we will use the prototype property of constructor functions. Prototype property on constructor functions will be referenced for every object we create. So our created object will not copy the properties that we define on the prototype property of the constructor but reference.

Now let’s create me object and see what its properties are:

As you can see me object only has 1 property called name. But if you look at the [[Prototype]] of me object it has our function sayMyName. It inherits this function from Human.prototype and we can use it. The important point is that sayMyName function is not copied its just referenced from Human.prototype.

So we will define the properties and methods, that we want to inherit, on the Constructor function’s prototype properties.

Conclusion

In conclusion, understanding the concepts of objects and prototypes in JavaScript is fundamental to becoming a proficient developer. Objects serve as the building blocks of the language, allowing us to encapsulate data and functionality in a structured manner. Meanwhile, prototypes establish the basis for inheritance, enabling the creation of efficient and reusable code.

By grasping these concepts, developers gain the ability to create scalable and maintainable code, unlocking the true power of JavaScript. Embracing the object-oriented nature of the language empowers us to design elegant solutions to complex problems, fostering modularity and extensibility in our applications.

As you delve deeper into JavaScript development, the knowledge of objects and prototypes will continue to be a valuable asset. Whether you're building simple scripts or complex web applications, a solid understanding of these core concepts will guide you towards writing more robust and efficient code. Keep exploring, experimenting, and applying these principles to enhance your JavaScript proficiency. Happy coding!

Resources