# How JavaScript Prototypes and the Prototype Chain Work: A Complete Guide

> Understand how JavaScript prototypes and the prototype chain enable inheritance. Learn how the engine traverses prototypes to find properties and methods.

- Repository: [Lydia Hallie/javascript-questions](https://github.com/lydiahallie/javascript-questions)
- Tags: deep-dive
- Published: 2026-03-04

---

**JavaScript implements inheritance through a prototype-based system where every object maintains an internal `[[Prototype]]` reference, and when property access fails on the object itself, the engine traverses the prototype chain upward until it locates the property or reaches `null`.**

The `lydiahallie/javascript-questions` repository contains detailed explanations of this mechanism, demonstrating how prototypes enable memory-efficient code sharing across object instances. This article breaks down the internal lookup process, constructor function patterns, and dynamic chain modification as documented in the project's README.

## What Is the Prototype Chain?

Every JavaScript object has an internal `[[Prototype]]` property, exposed in modern engines as `__proto__` or accessible via `Object.getPrototypeOf()`. When you access a property like `obj.property`, the engine performs the following steps:

1. Checks if the property exists as an own property on `obj`.
2. If not found, follows the `[[Prototype]]` link to the parent object.
3. Continues walking up the chain until finding the property or reaching `null`.

This linked-list structure of objects forms the **prototype chain**. According to the source code analysis in [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) (Lines 482-483), when a property is missing on the instance, "it goes down the prototype chain and finds it there."

## How Constructor Functions Use Prototypes

Functions act as constructors when invoked with the `new` keyword. Every function object automatically receives a `prototype` property, which becomes the `[[Prototype]]` of instances created from that constructor.

Adding methods to a constructor's **prototype** makes them available to all instances without duplicating the function in memory. As shown in the `lydiahallie/javascript-questions` README (Lines 404-410), you can define shared behavior like this:

```javascript
function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

// ✅ shared on the prototype
Person.prototype.getFullName = function () {
  return `${this.firstName} ${this.lastName}`;
};

const lydia = new Person('Lydia', 'Hallie');
console.log(lydia.getFullName()); // Lydia Hallie

```

When `lydia.getFullName()` executes, JavaScript first checks the `lydia` instance for the method. Finding none, it follows the prototype link to `Person.prototype` where the method resides, then invokes it with `this` bound to the instance.

## Modifying and Deleting Prototype Properties

The prototype chain is dynamic. You can add, modify, or remove properties from a prototype object at runtime, and these changes immediately affect all instances linked to that prototype.

Removing a property from a prototype breaks the chain for subsequent lookups. The README illustrates this at Lines 1711-1719:

```javascript
function Dog() {}
Dog.prototype.bark = function () { console.log('Woof!'); };

const dog = new Dog();
dog.bark(); // Woof!

delete Dog.prototype.bark; // removes the method from the chain
dog.bark(); // TypeError: dog.bark is not a function

```

Once `bark` is deleted from `Dog.prototype`, the lookup mechanism fails to find the method anywhere in the chain, resulting in a `TypeError`.

## Extending Built-in Object Prototypes

Built-in constructors like `String`, `Array`, and `Object` expose their own `prototype` objects. Extending these prototypes makes new methods available across all instances of that type.

As documented in [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) (Lines 855-859), adding a method to `String.prototype` works because primitive strings undergo temporary boxing into `String` objects during property access:

```javascript
String.prototype.giveLydiaPizza = () => '🍕';
console.log('hello'.giveLydiaPizza()); // 🍕

```

This technique, while powerful, modifies the global object space and can cause conflicts in large codebases or third-party libraries.

## Summary

- **Prototype-based inheritance** allows objects to inherit features from other objects through the internal `[[Prototype]]` link rather than class-based copying.
- **Constructor functions** utilize their `prototype` property to share methods across all instances created with `new`, optimizing memory usage.
- **Property lookup** traverses the prototype chain from the instance upward until finding the property or reaching `null`.
- **Dynamic modification** of prototypes immediately affects all linked instances, including the ability to delete properties and break the chain.
- **Built-in prototypes** like `String.prototype` can be extended, though this practice requires caution in production environments.

## Frequently Asked Questions

### How does `__proto__` differ from `prototype`?

The `prototype` property exists only on **constructor functions** and serves as the template for instances created with `new`. The `__proto__` accessor (or `Object.getPrototypeOf()`) exists on **all objects** and points to the object's immediate parent in the prototype chain. When you call `new Person()`, the resulting object's `__proto__` links to `Person.prototype`.

### Can you break the prototype chain intentionally?

Yes. You can break the chain by setting an object's prototype to `null` using `Object.setPrototypeOf(obj, null)` or by deleting properties from intermediate prototypes. Once broken, property lookups that previously succeeded will return `undefined` or throw `TypeError` for method calls, as the engine cannot traverse further up the chain.

### Why does extending `String.prototype` work on primitive strings?

JavaScript temporarily **boxes** primitive values into their object wrappers when you access properties on them. When you call `'text'.method()`, the engine converts the primitive string to a `String` object, looks up `method` on `String.prototype`, executes it, then discards the wrapper. This automatic boxing makes prototype extension appear to work on primitives.

### What happens when a property exists both on the instance and the prototype?

**Instance properties shadow prototype properties**. When accessing `obj.property`, the engine checks the instance first. If the property exists there, it returns the instance value immediately without traversing the chain. This allows individual instances to override shared defaults defined on the prototype.