Tutorials Logic, IN info@tutorialslogic.com

JavaScript Prototypes Prototype Chain: Tutorial, Examples, FAQs & Interview Tips

JavaScript Prototypes Prototype Chain

prototypes is an important JavaScript topic because it shows up in real projects, debugging sessions, and interviews. Learn the meaning first, then connect it to a small working example so the rule does not stay abstract.

Focus on what problem prototypes solves, where developers usually make mistakes, and how to verify the result with output, behavior, or a small test.

A strong understanding of prototypes should include syntax, behavior, one realistic use case, one failure case, and one quick way to check your work.

JavaScript Prototypes Prototype Chain should be studied as a practical JavaScript lesson, not as a label. Start by naming the input, the rule that changes the input, and the result a learner should be able to predict after reading the page.

In the javascript > prototypes page, the notes should connect the definition with a working scenario, a mistake that beginners actually make, and the exact check that proves the fix. That makes the topic useful for coding, debugging, and interview revision.

JavaScript Prototypes

JavaScript is a prototype-based language. This means objects can inherit properties and methods from other objects. Instead of copying every method into every object, JavaScript lets objects share behavior through a prototype chain.

Modern JavaScript has class syntax, but classes still use prototypes internally. Understanding prototypes helps you understand objects, inheritance, methods, this, new, class, and many interview questions much more clearly.

The Core Idea

When you access a property on an object, JavaScript first checks the object itself. If the property is not found, JavaScript looks at the object's prototype. If it is not found there, JavaScript continues up the prototype chain until it finds the property or reaches null.

The object user does not define toString, but it can still access it because ordinary objects inherit from Object.prototype.

Property Lookup

Property Lookup
const user = {
  name: 'Asha'
};

console.log(user.name);     // Asha - found on user
console.log(user.toString); // found on Object.prototype

// JavaScript looks like this:
// user -> Object.prototype -> null

Prototype vs prototype Property

This topic has confusing names, so separate these two ideas:

  • An object's internal prototype is the object it inherits from. It is often written as [[Prototype]].
  • A function's prototype property is used when that function is called with new.
  • The old __proto__ property points to an object's internal prototype, but prefer Object.getPrototypeOf().

Prototype Names

Prototype Names
function Student(name) {
  this.name = name;
}

const student = new Student('Riya');

console.log(Student.prototype); // object used for Student instances
console.log(Object.getPrototypeOf(student) === Student.prototype); // true

Constructor Functions and Prototypes

Before ES6 classes, constructor functions were the common way to create many similar objects. A constructor function is called with new. Methods should usually be placed on the constructor's prototype so all instances can share one method instead of creating a new function for every instance.

The two objects have different data, but they share the same introduce() method through Student.prototype.

Constructor Function

Constructor Function
function Student(name, course) {
  this.name = name;
  this.course = course;
}

Student.prototype.introduce = function() {
  return `${this.name} is learning ${this.course}.`;
};

const student1 = new Student('Aman', 'JavaScript');
const student2 = new Student('Neha', 'React');

console.log(student1.introduce()); // Aman is learning JavaScript.
console.log(student2.introduce()); // Neha is learning React.
console.log(student1.introduce === student2.introduce); // true

Instance Properties vs Prototype Properties

Properties placed directly on an instance belong only to that object. Properties placed on the prototype are shared through inheritance.

Instance vs Prototype

Instance vs Prototype
function Student(name) {
  this.name = name; // own property
}

Student.prototype.school = 'Tutorials Logic'; // shared prototype property

const student1 = new Student('Rohit');
const student2 = new Student('Kavya');

student1.age = 22; // only student1 has age

console.log(student1.name);   // Rohit
console.log(student1.school); // Tutorials Logic
console.log(student2.school); // Tutorials Logic
console.log(student2.age);    // undefined

The Prototype Chain

A prototype can also have its own prototype. This creates a chain. JavaScript walks this chain during property lookup.

Here, dog inherits from Dog.prototype, and Dog.prototype inherits from Animal.prototype. If JavaScript cannot find speak() on the dog itself or on Dog.prototype, it finds it on Animal.prototype.

Prototype Chain

Prototype Chain
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  return `${this.name} makes a sound.`;
};

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  return `${this.name} barks.`;
};

const dog = new Dog('Rex', 'Labrador');

console.log(dog.bark());  // Rex barks.
console.log(dog.speak()); // Rex makes a sound.

console.log(dog instanceof Dog);    // true
console.log(dog instanceof Animal); // true

Inspecting Prototypes

Use Object.getPrototypeOf() to inspect an object's prototype. Use Object.setPrototypeOf() rarely, because changing prototypes after objects are created can hurt performance and make code harder to reason about.

in checks the object and its prototype chain. Object.hasOwn() checks only the object's own properties.

Inspect Prototype Chain

Inspect Prototype Chain
const user = { name: 'Meera' };

console.log(Object.getPrototypeOf(user) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype));          // null

console.log('toString' in user); // true, inherited
console.log(Object.hasOwn(user, 'toString')); // false
console.log(Object.hasOwn(user, 'name'));     // true

Object.create()

Object.create() creates a new object with a specific prototype. It is a direct way to build prototype inheritance without using a constructor function.

Object.create()

Object.create()
const userMethods = {
  greet() {
    return `Hello, ${this.name}`;
  }
};

const user = Object.create(userMethods);
user.name = 'Anaya';

console.log(user.greet()); // Hello, Anaya
console.log(Object.getPrototypeOf(user) === userMethods); // true

Objects with No Prototype

Sometimes you may want a plain dictionary object with no inherited properties. Object.create(null) creates an object whose prototype is null. This can be useful for maps or lookup tables, though Map is often better in modern JavaScript.

No Prototype Object

No Prototype Object
const dictionary = Object.create(null);

dictionary.javascript = 'A programming language';
dictionary.prototype = 'An inheritance object';

console.log(dictionary.javascript);
console.log(dictionary.toString); // undefined
console.log(Object.getPrototypeOf(dictionary)); // null

Classes Use Prototypes Internally

The class syntax is the modern way to write constructor-style object code. It is easier to read, but instance methods are still stored on the class prototype.

The title property belongs to the instance. The getTitle() method belongs to Course.prototype and is shared by all Course instances.

Class Prototype

Class Prototype
class Course {
  constructor(title) {
    this.title = title;
  }

  getTitle() {
    return this.title;
  }
}

const jsCourse = new Course('JavaScript');

console.log(jsCourse.getTitle()); // JavaScript
console.log(Object.getPrototypeOf(jsCourse) === Course.prototype); // true
console.log(Course.prototype.getTitle === jsCourse.getTitle);      // true

Class Inheritance and Prototypes

When a class extends another class, JavaScript sets up a prototype chain between the child prototype and the parent prototype.

Class Inheritance

Class Inheritance
class Vehicle {
  constructor(make) {
    this.make = make;
  }

  describe() {
    return `Vehicle: ${this.make}`;
  }
}

class Car extends Vehicle {
  constructor(make, model) {
    super(make);
    this.model = model;
  }

  details() {
    return `${this.describe()} ${this.model}`;
  }
}

const car = new Car('Toyota', 'Camry');

console.log(car.details()); // Vehicle: Toyota Camry
console.log(Object.getPrototypeOf(Car.prototype) === Vehicle.prototype); // true

Static Methods and Constructor Inheritance

Classes also have a prototype relationship at the constructor level. This is why static methods can be inherited by child classes.

Instance methods are found through Formatter.prototype. Static methods are found through the constructor function itself.

Static Methods

Static Methods
class Tool {
  static category() {
    return 'Developer Tool';
  }
}

class Formatter extends Tool {}

console.log(Formatter.category()); // Developer Tool
console.log(Object.getPrototypeOf(Formatter) === Tool); // true

Shadowing Prototype Properties

If an object has its own property with the same name as a prototype property, the own property wins. This is called shadowing.

Property Shadowing

Property Shadowing
const defaults = {
  theme: 'light'
};

const settings = Object.create(defaults);

console.log(settings.theme); // light - inherited

settings.theme = 'dark';

console.log(settings.theme); // dark - own property shadows prototype
console.log(Object.hasOwn(settings, 'theme')); // true

Do Not Put Mutable Data on Prototypes

Prototype properties are shared. That is good for methods, but dangerous for mutable data such as arrays and objects. Put instance-specific data inside the constructor instead.

Shared Mutable Pitfall

Shared Mutable Pitfall
function TodoList() {}

// Bad: every instance shares the same array.
TodoList.prototype.items = [];

const personal = new TodoList();
const work = new TodoList();

personal.items.push('Buy milk');

console.log(work.items); // ['Buy milk'] - unexpected

// Better:
function SafeTodoList() {
  this.items = [];
}

Built-in Prototypes

Arrays, strings, dates, functions, and regular expressions all inherit methods from their built-in prototypes. For example, arrays get methods from Array.prototype.

Built-in Prototypes

Built-in Prototypes
const numbers = [1, 2, 3];

console.log(numbers.map(n => n * 2)); // [2, 4, 6]
console.log(Object.getPrototypeOf(numbers) === Array.prototype); // true
console.log(Object.getPrototypeOf(Array.prototype) === Object.prototype); // true

Avoid Modifying Built-in Prototypes

JavaScript allows you to add methods to built-in prototypes, but this is risky in production code. It can conflict with future JavaScript features, third-party libraries, or other team code.

Avoid This Pattern

Avoid This Pattern
// Possible, but usually not recommended.
Array.prototype.sum = function() {
  return this.reduce((total, number) => total + number, 0);
};

console.log([1, 2, 3].sum()); // 6

// Safer alternative:
function sum(numbers) {
  return numbers.reduce((total, number) => total + number, 0);
}

Prototype Pollution

Prototype pollution is a security problem where unsafe code lets user-controlled input modify shared prototypes such as Object.prototype. This can affect many objects in the application. Be careful when merging untrusted objects, especially if keys like __proto__, constructor, or prototype are allowed.

In real applications, use well-maintained libraries and keep dependencies updated. Avoid writing deep merge logic for untrusted data unless you fully understand the security risks.

Unsafe Merge Example

Unsafe Merge Example
function safeAssign(target, source) {
  for (const key of Object.keys(source)) {
    if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
      continue;
    }

    target[key] = source[key];
  }

  return target;
}

const settings = safeAssign({}, JSON.parse('{"theme":"dark"}'));
console.log(settings.theme); // dark

Prototype Methods vs Arrow Functions

Prototype methods usually need dynamic this, so regular functions are normally the right choice. Arrow functions do not have their own this, which can cause confusing bugs when used as prototype methods.

Use Regular Functions

Use Regular Functions
function User(name) {
  this.name = name;
}

// Good: regular function gets this from the call site.
User.prototype.greet = function() {
  return `Hello, ${this.name}`;
};

const user = new User('Dev');
console.log(user.greet()); // Hello, Dev

A Practical Prototype Example

The example below creates reusable course objects. Instance properties store each course's data, while prototype methods define shared behavior.

Course Constructor

Course Constructor
function Course(title, lessons) {
  this.title = title;
  this.lessons = lessons;
  this.completed = 0;
}

Course.prototype.completeLesson = function() {
  if (this.completed < this.lessons) {
    this.completed += 1;
  }
};

Course.prototype.getProgress = function() {
  return `${this.completed}/${this.lessons} lessons completed`;
};

const js = new Course('JavaScript Prototypes', 12);
js.completeLesson();
js.completeLesson();

console.log(js.getProgress()); // 2/12 lessons completed

Interview Explanation

If someone asks "What is a prototype in JavaScript?", answer with the object lookup idea first. Then mention constructor functions and classes.

A strong answer: "A prototype is an object that another object can inherit from. When JavaScript cannot find a property directly on an object, it searches that object's prototype chain. Constructor functions and classes use prototypes to share methods across instances."

Interview Answer

Interview Answer
function Person(name) {
  this.name = name;
}

Person.prototype.sayHi = function() {
  return `Hi, I am ${this.name}`;
};

const person = new Person('Asha');

console.log(person.sayHi()); // Hi, I am Asha
console.log(Object.getPrototypeOf(person) === Person.prototype); // true

Prototype Summary Table

Term Meaning
[[Prototype]] The internal link from one object to another object it inherits from.
Function.prototype The object assigned as the prototype of instances created with new.
Object.getPrototypeOf(obj) Returns the prototype of an object.
Object.create(proto) Creates a new object with proto as its prototype.
instanceof Checks whether a constructor's prototype appears in an object's prototype chain.
Object.hasOwn(obj, key) Checks whether a property belongs directly to the object.

Common Beginner Mistakes

  • Confusing a function's prototype property with an object's internal [[Prototype]].
  • Putting arrays or objects on a prototype and accidentally sharing mutable data.
  • Using arrow functions for prototype methods that need this.
  • Modifying built-in prototypes such as Array.prototype in production code.
  • Forgetting to reset constructor after replacing a prototype manually.
  • Assuming class removes prototypes. Classes still use prototypes internally.

Summary

Prototypes are the foundation of JavaScript inheritance. Every normal object can inherit from another object through its prototype. Constructor functions and classes use prototypes to share methods efficiently across instances. Once you understand property lookup, prototype chains, Object.create(), and how classes map to prototypes, JavaScript's object model becomes much easier to reason about.

JavaScript Prototypes Prototype Chain Java review example

JavaScript Prototypes Prototype Chain Java review example
class JavaScriptPrototypesPrototypeChainReview {
    public static void main(String[] args) {
        String state = "ready";
        System.out.println("JavaScript Prototypes Prototype Chain: " + state);
    }
}

JavaScript Prototypes Prototype Chain guard example

JavaScript Prototypes Prototype Chain guard example
String value = null;
if (value == null) {
    System.out.println("JavaScript Prototypes Prototype Chain: handle the missing value before continuing");
}
Key Takeaways
  • Explain the purpose of prototypes before memorizing syntax.
  • Trace the exact call expression and confirm which value reached the parentheses.
  • Test one normal case, one edge case, and one mistake case for prototypes.
  • Write down why the value is not callable and what should hold the function instead.
  • Connect prototypes to a real project scenario instead of treating it as an isolated definition.
Common Mistakes to Avoid
WRONG Calling a value before checking whether it actually holds a function reference.
RIGHT Trace the variable assignment, the property lookup, and the actual call expression.
Most beginner errors come from skipping the behavior behind the syntax.
WRONG Memorizing JavaScript Prototypes Prototype Chain without the situation where it is useful.
RIGHT Connect JavaScript Prototypes Prototype Chain to a concrete JavaScript task.
Purpose makes syntax easier to recall.
WRONG Testing JavaScript Prototypes Prototype Chain only with the perfect input.
RIGHT Include empty, missing, duplicate, incompatible, or failed cases when relevant.
Real bugs usually appear outside the perfect path.
WRONG Memorizing JavaScript Prototypes Prototype Chain without the situation where it is useful.
RIGHT Connect JavaScript Prototypes Prototype Chain to a concrete JavaScript task.
Purpose makes syntax easier to recall.

Practice Tasks

  • Modify the example so it guards with `typeof` or uses the correct method name.
  • Write one mistake related to prototypes, then fix it and explain the fix.
  • Summarize when to use prototypes and when another approach is better.
  • Write a small example that uses JavaScript Prototypes Prototype Chain in a realistic JavaScript scenario.
  • Change one important value in the JavaScript Prototypes Prototype Chain example and predict the result first.

Frequently Asked Questions

A prototype is an object that another object inherits from. If a property is not found directly on an object, JavaScript searches the prototype chain.

Classes are modern syntax for creating constructor-style objects, but they still use prototypes internally. Instance methods declared in a class are placed on the class prototype.

<code>prototype</code> is a property on functions used when creating instances with <code>new</code>. <code>__proto__</code> is an older accessor for an object's internal prototype. Prefer <code>Object.getPrototypeOf()</code> instead of <code>__proto__</code>.

Usually no. Modifying built-in prototypes like <code>Array.prototype</code> can cause conflicts with libraries, other code, or future JavaScript features.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.