---
title: Prototype
description: Share properties and methods among many objects of the same type through the prototype chain.
tokens: ~1026
---

# Prototype

The Prototype pattern lets objects share behavior through a linked prototype object instead of duplicating it on every instance. In JavaScript this is built into the language — every object has an internal `[[Prototype]]` link that the engine follows when a property isn't found on the object itself.

## How It Works

Consider a factory function that creates many similar objects:

```typescript
const createDog = (name: string, age: number) => ({
  name,
  age,
  bark() {
    console.log(`${name} is barking!`);
  },
  wagTail() {
    console.log(`${name} is wagging their tail!`);
  },
});

const dog1 = createDog("Max", 4);
const dog2 = createDog("Sam", 2);
```

Every call produces a brand-new copy of `bark` and `wagTail`. With four dogs you have eight function objects in memory doing the same thing.

The Prototype pattern avoids this by placing shared methods on a single prototype object. All instances delegate to it instead of owning their own copies.

### Using a Class

ES6 classes wire up the prototype chain automatically. Methods defined in the class body live on `ClassName.prototype` and are shared across all instances.

```typescript
class Dog {
  constructor(
    public name: string,
    public age: number,
  ) {}

  bark() {
    console.log(`${this.name} is barking!`);
  }

  wagTail() {
    console.log(`${this.name} is wagging their tail!`);
  }
}

const dog1 = new Dog("Max", 4);
const dog2 = new Dog("Sam", 2);

dog1.bark(); // "Max is barking!"
dog2.wagTail(); // "Sam is wagging their tail!"
```

`dog1` and `dog2` don't carry their own `bark` or `wagTail`. When you call `dog1.bark()`, the engine doesn't find `bark` on `dog1` itself, walks up to `Dog.prototype`, and finds it there.

### Using `Object.create`

You can also set up a prototype chain without classes using `Object.create`, which creates a new object with the specified object as its prototype:

```typescript
const dogPrototype = {
  bark(this: { name: string }) {
    console.log(`${this.name} is barking!`);
  },
  wagTail(this: { name: string }) {
    console.log(`${this.name} is wagging their tail!`);
  },
};

const dog1 = Object.create(dogPrototype);
dog1.name = "Max";
dog1.age = 4;

dog1.bark(); // "Max is barking!"
```

`Object.create(dogPrototype)` returns an empty object whose `[[Prototype]]` points to `dogPrototype`. Property lookups that fail on `dog1` fall through to the prototype.

## The Prototype Chain

Prototypes can themselves have prototypes, forming a chain. The engine walks the chain until it finds the property or reaches `null`.

```typescript
class Animal {
  constructor(public name: string) {}
  eat() {
    console.log(`${this.name} is eating`);
  }
}

class Dog extends Animal {
  bark() {
    console.log(`${this.name} is barking!`);
  }
}

class BorderCollie extends Dog {
  herd() {
    console.log(`${this.name} is herding`);
  }
}

const rex = new BorderCollie("Rex");
rex.herd(); // found on BorderCollie.prototype
rex.bark(); // found on Dog.prototype
rex.eat(); // found on Animal.prototype
```

## Trade-Offs

| Advantage                                                    | Disadvantage                                                                |
| ------------------------------------------------------------ | --------------------------------------------------------------------------- |
| Memory efficient — methods are stored once, not per instance | Deep prototype chains can make it hard to trace where a property comes from |
| Easy to add or change shared behavior in one place           | Modifying a prototype at runtime affects all existing instances             |
| Built into JavaScript — no extra library needed              | `this` binding surprises when methods are passed as callbacks               |

## When to Use It

- You're creating many objects that share the same methods and want to avoid duplicating functions in memory.
- You want a lightweight inheritance hierarchy where child types extend a base with additional behavior.
- You need to add shared behavior after object creation (by attaching methods to the prototype).