Year End Sale: Get Upto 40% OFF on Live Training! Offer Ending in
D
H
M
S
Get Now
A Complete Guide to Prototypes in JavaScript: How They Work and Why They Matter

A Complete Guide to Prototypes in JavaScript: How They Work and Why They Matter

09 Dec 2024
Beginner
66 Views
37 min read
Learn with an interactive course and practical hands-on labs

Free Javascript Course: Learn Javascript In 21 Days

Prototype in JavaScript

Prototypes in JavaScript might sound a bit technical at first, but they’re simpler than you think. Have you ever wondered how objects in JavaScript can share methods or properties without copying them everywhere? That is where prototypes come in, and they make it all happen behind the scenes.

In this JavaScript tutorial, we will explore what prototypes are, how they work, and why they are a game-changer for your JavaScript code. By the end, you will feel confident using prototypes to build smarter, reusable, and more efficient applications.

Read More: Defining Namespace or Nested Objects in JavaScript

Importance of prototypes in object creation and inheritance

Have you ever needed to create multiple objects that share the same behavior? Instead of repeating the same code, you can use prototypes to make your work easier. They let you define properties and methods once and reuse them across all your objects.

With prototypes, you do not have to worry about writing duplicate code. It allows you to share methods between objects efficiently, saving memory and making your code cleaner. Doesn’t that sound like a smarter way to handle inheritance in JavaScript? Understanding prototypes helps you build faster, scalable, and more maintainable applications.

Read More: Understanding Inheritance and Different Types of Inheritance

JavaScript Prototype Illustration

When you work with JavaScript, understanding prototypes is essential. It's like discovering how objects share properties and methods without copying them. Prototypes let you create a chain of relationships between objects, making your code more efficient and easier to manage.

1. Visual and Code-Based Demonstration of Prototype Relationships

Prototypes work behind the scenes to connect objects. It's like a hidden chain where objects can "borrow" properties or methods from another object. Let’s explore this with a simple example:


// A base object with a method
const vehicle = {
    start: function() {
        return "Vehicle started";
    }
};

// A car object linked to the vehicle prototype
const car = Object.create(vehicle);
car.wheels = 4;

// Using the inherited method and own property
console.log(car.start()); // "Vehicle started"
console.log(car.wheels);  // 4
    

Output:


Vehicle started
4

Explanation:

  • vehicle: This is a base object that contains a method start.
  • car: This object is created using Object.create(vehicle), so it inherits from vehicle.
  • Inheritance: The car object can use the start method defined in vehicle.
  • Own property: The car object has its own property, wheels, which is set to 4.
  • Output: The program prints "Vehicle started" from the inherited method and 4 from its own property.

Real-World Examples Showing Prototype Linkage

Think of prototypes like building blocks. Here’s a relatable example:

Example: Library System

In a library, you might have books with common properties like "borrowed status."
    
    // Prototype for all books
    const book = {
        borrowed: false,
        borrow: function() {
            this.borrowed = true;
            return `${this.title} has been borrowed.`;
        }
    };
    
    // Specific book linked to the book prototype
    const specificBook = Object.create(book);
    specificBook.title = "JavaScript Basics";
    
    console.log(specificBook.borrow()); // "JavaScript Basics has been borrowed."
    console.log(specificBook.borrowed); // true
        

    Output:

    
    JavaScript Basics has been borrowed.
    true
    

    Explanation:

    • book: This is a prototype object representing the base behavior of books. It has a property borrowed and a method borrow that changes the borrowed status to true.
    • specificBook: This is an object created using Object.create(book). It inherits the borrow method from the book prototype.
    • title property: The specificBook object gets its own title property, set to "JavaScript Basics."
    • Inheritance in action: When calling specificBook.borrow(), it updates the inherited borrowed property to true and returns a message using the title.
    • Output: The program prints the borrowing message and confirms that the book is now marked as borrowed.

    Defining Methods in the JavaScript Prototype Object

    In JavaScript, you can define methods directly on an object's prototype, allowing all instances of that object to share the same method. This saves memory and makes your code more efficient. It’s like giving a group of objects a common set of tools, so they don’t each need their own individual copy of the tools.

    Adding Methods to an Object's Prototype for Reuse

    When you add a method to a prototype, it is available to all instances of that object. This means that instead of duplicating the method for each object, you can reuse it across many objects. Let's look at how to do this:

    Example: Defining Shared Methods in Prototypes

    
    // Constructor function to create a new object
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    
    // Define a shared method on the prototype
    Person.prototype.greet = function() {
        return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
    };
    
    // Creating instances of Person
    const person1 = new Person("Alice", 30);
    const person2 = new Person("Bob", 25);
    
    // Using the shared method
    console.log(person1.greet()); // "Hello, my name is Alice and I am 30 years old."
    console.log(person2.greet()); // "Hello, my name is Bob and I am 25 years old."
        

    Output:

    
    Hello, my name is Alice and I am 30 years old.
    Hello, my name is Bob and I am 25 years old.
    

    Explanation:

    • In this example, we define the greet method on the prototype of the Person constructor function.
    • Both person1 and person2 are instances of the Person constructor, and they both share the same greet method, which is stored on the prototype.
    • By sharing the method, memory is optimized because there is only one copy of the greet method, regardless of how many objects are created.
    Practice with these Articles:

    Defining Methods with Constructor Functions in JavaScript

    • In JavaScript, a constructor function is used to create objects with similar properties and methods.
    • You define methods inside the constructor function to give each instance of an object its behavior.
    • The constructor function itself is used with the new keyword to create new objects.

    Adding methods to a constructor function's prototype for reuse

    • When you add methods to the prototype of a constructor function, all instances of that constructor share the same method.
    • This is more memory efficient, especially when many instances are created.
    The prototype allows you to define methods that are shared by all instances created by the constructor function.

    Example: Creating Person objects and adding a greet method

    
    // Define a constructor function for creating 'Person' objects
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    
    // Add a method to the 'Person' prototype
    Person.prototype.greet = function() {
        return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
    };
    
    // Create new instances of Person
    const person1 = new Person("Alice", 25);
    const person2 = new Person("Bob", 30);
    
    // Both instances can use the greet method defined in the prototype
    console.log(person1.greet()); // "Hello, my name is Alice and I am 25 years old."
    console.log(person2.greet()); // "Hello, my name is Bob and I am 30 years old."
        

    Output:

    
    Hello, my name is Alice and I am 25 years old.
    Hello, my name is Bob and I am 30 years old.
    

    Explanation:

    • Person constructor: The constructor function Person is used to create new objects with name and age properties.
    • Prototype method: The greet method is added to the prototype of Person, so all instances of Person will inherit this method.
    • Creating instances: Two instances, person1 and person2, are created using the new keyword and the Person constructor.
    • Method invocation: The greet method is invoked in both instances, which returns a personalized greeting using the name and age of each person.
    • Output: The output shows the greeting for each person as defined in the greet method.

      Defining Methods in an Individual Object

      In JavaScript, you can add methods directly to an individual object rather than adding them to the object's prototype. This means that only that specific object will have the method, making it unique to that object. Unlike prototype methods, which are shared among all instances of an object, methods added directly to an object cannot be reused by others unless explicitly added.

      Adding methods directly to a single object

      This approach is useful when you need a method that is only relevant to a specific instance of an object. It’s like giving that particular object a custom feature.

      Example: Adding methods directly to an individual object

      
      // Create an individual object
      const person = {
          name: "Alice",
          age: 25
      };
      
      // Add a method directly to this object
      person.greet = function() {
          return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
      };
      
      console.log(person.greet()); // "Hello, my name is Alice and I am 25 years old."
          

      Explanation:

      • person object: The object is created with properties name and age.
      • greet method: The method greet is added directly to the person object. This method returns a greeting message using the object's properties.
      • Output: The method is called on the person object and logs the personalized greeting.

      Comparison Between Individual Object Methods and Prototype Methods

      JavaScript offers two ways to add methods to objects: through prototypes or directly on individual objects. The choice depends on whether the method should be shared across all instances or be unique to a specific object. Here, we compare the two approaches to understand their benefits and drawbacks.

      Prototype Methods vs. Individual Object Methods

      Prototype Methods: These are shared by all instances of the object, meaning they use less memory. Any change to the method affects all instances of the object.

      Individual Object Methods: These methods are only available to that specific object, and can’t be shared with other instances unless added explicitly.

      Getting Prototype Linkage

      Understanding how JavaScript objects are linked to their prototypes is crucial for inheritance. When accessing properties or methods, JavaScript will check the object's prototype chain to find them. Knowing how to retrieve and inspect this prototype linkage can help you understand how inheritance works.

      Understanding Prototype Chains

      Prototype chains allow objects to inherit properties and methods from their prototypes. When JavaScript looks for a property or method, it first checks the object itself. If it doesn’t find the property, it will look at the prototype, and so on, up the prototype chain.

      Example using Object.getPrototypeOf

      
      const person = {
          name: "Alice"
      };
      
      const prototype = Object.getPrototypeOf(person);
      console.log(prototype); // Will show Object.prototype
          

      Example using __proto__

      
      const person = {
          name: "Alice"
      };
      
      console.log(person.__proto__); // Will show Object.prototype
          

      Shadowing

      In JavaScript, an object can shadow or override a property or method inherited from its prototype. This happens when an object defines a property or method with the same name as one in its prototype, causing the object’s property to take precedence.

      Property and Method Shadowing in Prototypes

      Shadowing occurs when an object defines a property or method with the same name as one in its prototype. The property or method in the object will be used instead of the one in the prototype.

      Example: Overriding Prototype Properties or Methods

      
      const person = {
          name: "Alice",
          greet: function() {
              return "Hello from prototype!";
          }
      };
      
      // Overriding the greet method
      person.greet = function() {
          return "Hello from Alice!";
      };
      
      console.log(person.greet()); // "Hello from Alice!" (Shadows the prototype method)
          

      Prototype Inheritance

      Prototype inheritance is a powerful feature in JavaScript that allows objects to inherit properties and methods from other objects. This is the basis for object-oriented programming in JavaScript.

      Read More: Object-Oriented Programming Concepts

      Using Prototypes for Property and Method Inheritance

      Objects can inherit from other objects by linking to their prototype. When an object inherits from a prototype, it can access all the properties and methods defined on that prototype, even if those properties are not directly part of the object.

      Example: Inheriting from a Prototype

      
      const animal = {
          sound: "Roar",
          makeSound: function() {
              return this.sound;
          }
      };
      
      // Create a new object that inherits from animal
      const lion = Object.create(animal);
      lion.name = "Lion";
      
      console.log(lion.name);        // "Lion"
      console.log(lion.makeSound()); // "Roar" (inherited from animal)
          

      JavaScript Prototype Chaining

      JavaScript's prototype chaining mechanism allows objects to inherit properties and methods not just from their own properties but also from their prototype’s properties. This chain continues until it reaches Object.prototype.

      Explanation of Prototype Chain Resolution

      When JavaScript looks for a property or method, it starts with the object itself. If it doesn't find it, it searches the prototype and then the prototype's prototype, continuing up the chain. The search ends when it reaches Object.prototype.

      Example: Prototype Chain Traversal

      
      const person = {
          name: "Alice"
      };
      
      const employee = Object.create(person);
      employee.position = "Developer";
      
      console.log(employee.name); // "Alice" (inherited from person)
      console.log(employee.position); // "Developer" (own property)
          

      Functional Instantiation and Prototypal Patterns

      Functional instantiation is a common pattern in JavaScript that allows objects to be created via functions. By using constructor functions or the Object.create() method, you can manage object creation and inheritance. These patterns are fundamental to understanding object-oriented principles in JavaScript.

      Functional Instantiation

      Functional instantiation refers to creating objects using functions. In JavaScript, this is often done by defining a function that acts as a constructor. When you call the function using the new keyword, it creates a new object with the properties and methods defined in the constructor.

      Creating Objects Through Functions

      In this approach, you define a function and use it to generate new objects. When you use the new keyword, it automatically sets up the this context for the function, allowing you to assign properties and methods to the new object.

      Example: Using a Constructor Function

      
      // Constructor function to create a new object
      function Person(name, age) {
          this.name = name;
          this.age = age;
          this.greet = function() {
              return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
          };
      }
      
      // Creating a new object using the constructor function
      const person1 = new Person("Alice", 30);
      console.log(person1.greet()); // "Hello, my name is Alice and I am 30 years old."
          

      Output:

      
      Hello, my name is Alice and I am 30 years old.
      

      Explanation:

      • The constructor function Person is used to create new objects with properties name and age, as well as a method greet.
      • When the object person1 is created using the new keyword, the constructor initializes the object's properties.
      • The greet method outputs a message that includes the object's name and age.

      Functional Instantiation with Shared Methods

      To improve memory usage, you can share methods across all instances of an object by defining them outside the constructor function. This avoids creating duplicate methods for every instance and helps optimize memory usage.

      Sharing Methods Across Instances to Save Memory

      By placing methods outside the constructor, you ensure that all instances of the object share the same method, which reduces memory overhead. This technique is commonly used with the Prototype Design Pattern

      Read More: Different Types of Design Patterns

      Example: Defining Shared Methods Outside the Constructor

      
      // Constructor function with shared method outside
      function Person(name, age) {
          this.name = name;
          this.age = age;
      }
      
      // Shared method defined on the prototype
      Person.prototype.greet = function() {
          return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
      };
      
      const person2 = new Person("Bob", 25);
      console.log(person2.greet()); // "Hello, my name is Bob and I am 25 years old."
          

      Output:

      
      Hello, my name is Bob and I am 25 years old.
      

      Explanation:

      • The greet method is shared across all instances of Person because it is defined on the prototype, which helps reduce memory usage.
      • Even though each Person instance has its own properties, they all share the same greet method.

      Object.create

      Object.create() is a method that allows you to create an object with a specified prototype. This method provides a simpler way to establish prototype chains and inherit properties from other objects.

      Using Object.create to Set Up Prototype Chains

      Object.create() is used to create a new object with an explicit prototype, which can then be extended or modified as needed. This method is often used for inheritance when you want to set the prototype of a new object directly.

      Explanation and Practical Examples

      Using Object.create(), you can easily set up inheritance and prototype chains. This method provides a more flexible and explicit way to link objects and define inheritance than constructor functions alone.

      Example: Using Object.create

      
      // Creating an object with Object.create
      const animal = {
          sound: "Roar",
          makeSound: function() {
              return this.sound;
          }
      };
      
      // Create a new object that inherits from animal
      const lion = Object.create(animal);
      lion.name = "Lion";
      
      console.log(lion.name); // "Lion"
      console.log(lion.makeSound()); // "Roar"
          

      Output:

      
      Lion
      Roar
      

      Explanation:

      • The lion object is created using Object.create(animal), which sets the prototype of lion to be animal.
      • The lion object inherits the makeSound method from animal and can access its own properties, like name.

      Functional Instantiation with Shared Methods and Object.create

      This hybrid approach combines the benefits of functional instantiation, where you can define shared methods outside the constructor, with the flexibility of Object.create() to set up prototype chains.

      Combining the Benefits of Shared Methods and Object.create

      By using Object.create() to set up inheritance and defining methods on the prototype, you can create efficient objects that share common methods but still allow for individual properties and customization.

      Code Examples Illustrating This Hybrid Approach

      
      // Constructor function with shared method on the prototype
      function Person(name, age) {
          this.name = name;
          this.age = age;
      }
      
      // Shared method defined on the prototype
      Person.prototype.greet = function() {
          return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
      };
      
      // Creating an object with Object.create
      const person3 = Object.create(Person.prototype);
      person3.name = "Charlie";
      person3.age = 28;
      
      console.log(person3.greet()); // "Hello, my name is Charlie and I am 28 years old."
          

      Output:

      
      Hello, my name is Charlie and I am 28 years old.
      

      Explanation:

      • The object person3 is created using Object.create(Person.prototype), setting its prototype to Person.
      • The object shares the greet method defined on the Person prototype, while having its own properties name and age.

      Prototypal Instantiation

      Prototypal instantiation allows you to create objects directly from other objects, without using constructor functions. This is the most direct way of setting up inheritance in JavaScript.

      Directly Creating Objects from Other Objects

      With prototypal instantiation, you create a new object by using another object as its prototype. This method avoids the need for constructors and allows direct object inheritance.

      Example: Leveraging Object Literals and Inheritance with Prototypes

      
      // Create an object directly from another object
      const animal = {
          sound: "Roar",
          makeSound: function() {
              return this.sound;
          }
      };
      
      // Directly creating an object that inherits from animal
      const lion2 = Object.create(animal);
      lion2.name = "Lion";
      
      console.log(lion2.name);        // "Lion"
      console.log(lion2.makeSound()); // "Roar"
          

      Output:

      
      Lion
      Roar
      

      Explanation:

      • The object lion2 is created directly from the animal object using Object.create().
      • lion2 inherits the makeSound method from the animal prototype and also has its own properties like name.

      Summary
      This article covered how to define methods inside constructor functions and add them to the prototype for reuse in JavaScript. Constructor functions create objects with specific properties, and defining methods in the prototype allows all instances of that constructor to share the same method, saving memory. Using the prototype is an efficient way to add common behavior to multiple objects.

      Want to learn more about JavaScript? Sign up for the ScholarHat JavaScript Programming Course today and become a JavaScript pro! Don't miss your chance to improve your skills and take your career to the next level!

      FAQs

      The purpose of a prototype in JavaScript is to allow objects to inherit properties and methods from other objects. It enables you to share functionality across instances, making code reusable and memory-efficient.

      In JavaScript, a prototype is an object from which other objects inherit properties and methods. It allows you to add shared functionality to multiple instances of an object, supporting inheritance and code reuse in JavaScript.

      You should use JavaScript prototypes when you want to share properties and methods among multiple instances of an object. This is useful for inheritance, reducing memory usage, and promoting code reusability. It’s ideal for defining common behavior across objects in a more efficient way.

      To get a value from a prototype in JavaScript, you can access it using the object's prototype chain. For example, if you have a method or property defined on the prototype, you can access it via the object like this: 
      function Person(name) {
        this.name = name;
      }
      
      Person.prototype.greet = function() {
        return `Hello, ${this.name}`;
      };
      
      const person1 = new Person('John');
      console.log(person1.greet());  // Accessing the prototype metho
      In this case, greet is defined on the prototype of Person, and we access it through person1.

      Take our Javascript skill challenge to evaluate yourself!

      In less than 5 minutes, with our skill challenge, you can identify your knowledge gaps and strengths in a given skill.

      GET FREE CHALLENGE

      Share Article
      About Author
      Shailendra Chauhan (Microsoft MVP, Founder & CEO at Scholarhat by DotNetTricks)

      Shailendra Chauhan, Founder and CEO of ScholarHat by DotNetTricks, is a renowned expert in System Design, Software Architecture, Azure Cloud, .NET, Angular, React, Node.js, Microservices, DevOps, and Cross-Platform Mobile App Development. His skill set extends into emerging fields like Data Science, Python, Azure AI/ML, and Generative AI, making him a well-rounded expert who bridges traditional development frameworks with cutting-edge advancements. Recognized as a Microsoft Most Valuable Professional (MVP) for an impressive 9 consecutive years (2016–2024), he has consistently demonstrated excellence in delivering impactful solutions and inspiring learners.

      Shailendra’s unique, hands-on training programs and bestselling books have empowered thousands of professionals to excel in their careers and crack tough interviews. A visionary leader, he continues to revolutionize technology education with his innovative approach.
      Accept cookies & close this