# Prototypes: What Classes Are Made Of

Underneath every class, each object is linked to a prototype object that holds the shared methods, and JavaScript finds a property by walking that chain of links until it finds it or runs out.

Freelancer · JavaScript · OOP · Updated November 1, 2026

## After this lesson you can

- Explain how JavaScript finds a property by walking the prototype chain
- Tell an object's own properties from inherited ones with Object.hasOwn and Object.getPrototypeOf

## Key takeaways

- An object's own properties, such as name, sit on the object itself. Its methods sit on its prototype, one shared copy for every instance.
- To find a property, JavaScript looks at the object, then its prototype, then that prototype's prototype, and stops at the first match. That path is the prototype chain.
- A fighter's chain runs Fighter.prototype, then Ship.prototype, then Object.prototype, then null, which ends it.
- Object.getPrototypeOf(x) shows x's prototype, and Object.hasOwn(x, "name") tells an own property from an inherited one.
- A class is a neater way to write what older code builds by hand with a function and its prototype.

Sooner or later you'll read code written before JavaScript had classes, with lines like `Ship.prototype.describe = function () { ... }`. You'll see `[[Prototype]]` when you open an object in the browser's DevTools, and you'll meet a bug where an object seems to have a property it was never given. All of them come from one idea: **prototypes**, what a class actually builds underneath. This lesson is the advanced end of the chapter. Your classes work without it, but knowing it means nothing about objects is magic anymore.

## Where do the methods live?

Every `Ship` you build has a `describe` method. But is a copy of `describe` stored in every ship? Let's ask JavaScript. **`Object.hasOwn(object, "name")`** answers `true` when the property sits on the object itself:

```javascript
class Ship {
  constructor(name) {
    this.name = name;
  }

  describe() {
    return `${this.name} is ready`;
  }
}

const comet = new Ship("Comet");

console.log(Object.hasOwn(comet, "name"));
console.log(Object.hasOwn(comet, "describe"));
console.log(Object.getPrototypeOf(comet) === Ship.prototype);
console.log(Object.hasOwn(Ship.prototype, "describe"));
```

```text
true
false
true
true
```

`name` is Comet's **own property**: the constructor put it on Comet. `describe` isn't. It lives on a separate object, `Ship.prototype`, and every ship is linked to that object. **`Object.getPrototypeOf(comet)`** shows the object Comet is linked to: its **prototype**. A property an object reaches through that link, such as Comet's `describe`, is an **inherited property**.

## Ask here, then ask up the chain

Think of a help desk in a big store. You ask the person at the counter; if they don't know, they ask their manager, and the manager asks the head office. Someone up the line usually knows, and you never see the asking.

That's how JavaScript reads `comet.describe`. It looks at Comet itself first. Not there? It looks at Comet's prototype, `Ship.prototype`, and finds it. With a `Fighter`, the line is longer:

```javascript
class Ship {
  describe() {
    return "a ship";
  }
}

class Fighter extends Ship {
  fire() {
    return "pew!";
  }
}

const comet = new Fighter();

let link = Object.getPrototypeOf(comet);
while (link !== null) {
  console.log(link.constructor.name);
  link = Object.getPrototypeOf(link);
}
```

```text
Fighter
Ship
Object
```

The loop follows the links one at a time, printing the class each prototype belongs to. Comet's prototype is `Fighter.prototype` (which has `fire`), whose prototype is `Ship.prototype` (which has `describe`), whose prototype is `Object.prototype`, whose prototype is `null`: the end of the line. That path is the **prototype chain**, and it's what `extends` builds.

![A chain of four links: the comet object, then Fighter.prototype with fire, then Ship.prototype with describe, then Object.prototype with toString; a lookup of comet.describe starts at comet and moves down the chain until it finds describe on Ship.prototype](https://fsdtrainingmedia.blob.core.windows.net/public/images/2026/10/5fa40c23007b4297a85351e543c056b3.webp)

## Things you never wrote

That last link explains a mystery. Every object, even one with no methods at all, can do this:

```javascript
class Ship {}

const comet = new Ship();

console.log(comet.toString());
console.log(Object.hasOwn(comet, "toString"));
```

```text
[object Object]
false
```

You never wrote `toString`. JavaScript didn't find it on Comet or on `Ship.prototype`, and kept going to `Object.prototype`, the end of almost every chain, which gives every object a handful of built-in methods. When a property isn't anywhere on the chain, the answer is `undefined`.

The chain is also what **`instanceof`** checks: `comet instanceof Ship` is `true` when `Ship.prototype` is somewhere on Comet's chain, so a fighter is an instance of `Fighter` *and* of `Ship`.

**Try it.** Make `chain.js` with the `Fighter` example, and add `class Freighter extends Ship {}` above `const comet`. Print `comet instanceof Fighter`, `comet instanceof Ship` and `comet instanceof Freighter`, and explain each answer with the chain.

## One copy for every instance

Because methods live on the prototype, every ship shares one copy:

```javascript
class Ship {
  constructor(name) {
    this.name = name;
  }

  describe() {
    return `${this.name} is ready`;
  }
}

const comet = new Ship("Comet");
const vega = new Ship("Vega");

console.log(comet.describe === vega.describe);
console.log(comet.name === vega.name);
console.log(typeof Ship);
```

```text
true
false
function
```

`comet.describe === vega.describe` (`===` is read "strictly equal") is `true`: it's the very same function, so a game with a thousand ships stores `describe` once. Each ship's own data is separate. And `typeof Ship` says `function`: underneath, a class is a special function with a `prototype` object attached.

## An own property wins

The lookup stops at the **first** match. So if an object gets an own property with the same name as one on its prototype, its own property hides the shared one, for that object only:

```javascript
class Ship {
  constructor(name) {
    this.name = name;
  }

  describe() {
    return `${this.name} is ready`;
  }
}

const comet = new Ship("Comet");
const vega = new Ship("Vega");

vega.describe = function () {
  return `${this.name} is ready, and showing off`;
};

console.log(comet.describe());
console.log(vega.describe());
console.log(Object.hasOwn(vega, "describe"));
```

```text
Comet is ready
Vega is ready, and showing off
true
```

Vega's own `describe` is found first, so the search never reaches `Ship.prototype`. Comet has no own `describe` and still gets the shared one. Overriding with `extends` works the same way, one link up: `Fighter.prototype.describe` is found before `Ship.prototype.describe`.

## Before classes: the same thing by hand

Classes arrived in JavaScript in 2015. Before that, programmers built the same chain by hand, and you'll still meet this style in older code and tutorials:

```javascript
function OldShip(name) {
  this.name = name;
}

OldShip.prototype.describe = function () {
  return `${this.name} is ready`;
};

const relic = new OldShip("Relic");
console.log(relic.describe());
console.log(Object.getPrototypeOf(relic) === OldShip.prototype);
```

```text
Relic is ready
true
```

A function called with `new` plays the constructor, and methods are added to its `prototype` object one by one. A class writes the same thing more neatly, which is why it's sometimes called *syntactic sugar*: a sweeter way to write something the language could already do. When you see `.prototype.` in old code, read it as "a method every instance shares".

## Check yourself

2 questions to try on the lesson page.

## So what

Every class, every `extends` and every method call runs on the prototype chain. When an object has a property you didn't expect, or an override doesn't seem to take, walk the chain with `Object.getPrototypeOf` and `Object.hasOwn`, and you'll see exactly where JavaScript found it.

## Key terms

- [Prototype](https://www.ask-codey.com/glossary/prototype)
- [Prototype Chain](https://www.ask-codey.com/glossary/prototype-chain)
- [Own Property](https://www.ask-codey.com/glossary/own-property)
- [Inherited Property](https://www.ask-codey.com/glossary/inherited-property)
- instanceof

## Cheat sheets

- [Prototypes: What Classes Are Made Of](https://www.ask-codey.com/cheat-sheets/javascript-classes-prototypes-cheat-sheet)

## Related

- [Inheritance with extends and super](https://www.ask-codey.com/lessons/javascript-classes-extends-and-super)
- [Classes: Blueprints for Objects](https://www.ask-codey.com/lessons/javascript-classes-blueprints)

Source: https://www.ask-codey.com/lessons/javascript-classes-prototypes
