Menu

JavaScript Prototypes: The Chain Behind Every Object

What JavaScript prototypes actually are, how the prototype chain resolves property lookups, and how class syntax maps onto the same underlying mechanism.

Every Object Has a Prototype

JavaScript is a prototype-based language. That sounds exotic, but the idea is simple: every object has a secret link to another object — its prototype — and when you ask for a property the object doesn't have, JavaScript follows the link and asks there.

index.js
Output
Click Run to see the output here.

rabbit doesn't have an eats property of its own. JavaScript checks rabbit, doesn't find it, follows the prototype link to animal, finds eats: true, and returns it. For flies, it walks the chain, finds nothing, and returns undefined.

This lookup-and-walk behaviour is the whole mechanism. Inheritance, methods, class — all of it is built on this.

The Prototype Chain

The chain doesn't stop at one step. A prototype can have its own prototype, and so on, until you hit null:

index.js
Output
Click Run to see the output here.

Run it and you'll see rabbit, then Object.prototype, then null. That's why rabbit.toString() works even though you never defined toString — it lives on Object.prototype, the top of almost every chain.

Property lookup walks this chain from the bottom up. Assignment, on the other hand, always writes to the object itself — it never reaches up. That asymmetry is important and surprises people regularly.

Constructor Functions and .prototype

Before class existed, the standard way to make many similar objects was a constructor function called with new:

index.js
Output
Click Run to see the output here.

Two things happen when you call new User("Ada"):

  1. A fresh object is created, with its prototype set to User.prototype.
  2. User runs with this bound to that new object.

greet isn't copied onto each instance. It lives once on User.prototype, and both ada and boris find it by walking their chain. That's why the last line prints true — it's literally the same function.

prototype vs __proto__

These two names trip everyone up. They're related but not the same thing.

  • User.prototype is a property on the constructor function. It's the object that becomes the prototype of instances made with new User(...).
  • ada.__proto__ (or Object.getPrototypeOf(ada)) is the link on the instance pointing up to its prototype.
index.js
Output
Click Run to see the output here.

Prefer Object.getPrototypeOf(obj) over obj.__proto__ in new code. __proto__ is a legacy accessor kept around for compatibility; the function is the official API.

Classes Are Sugar Over This

Modern JavaScript lets you write class, but underneath, you're still dealing with prototypes. Compare the two versions side by side:

index.js
Output
Click Run to see the output here.

greet landed on User.prototype, same as if you'd written it by hand. The class keyword mostly gives you tidier syntax, stricter rules (you must use new), and a cleaner way to do extends — but the runtime model is identical.

Knowing this matters when you read error messages or debug this. An error about "User.prototype.greet" isn't a weird internal name — it's exactly where the method lives.

Inheritance Is Just Longer Chains

extends chains one prototype to another. The parent's prototype becomes the child's prototype's prototype:

index.js
Output
Click Run to see the output here.

Looking up rex.eat walks rexDog.prototypeAnimal.prototype, finds eat there, and calls it with this still bound to rex. That's all extends does — it sets up the chain for you.

Creating Objects Directly With a Prototype

You don't need a constructor at all. Object.create(proto) makes a new object with the prototype you specify:

index.js
Output
Click Run to see the output here.

No class, no new, no constructor function. Two objects sharing one method through a shared prototype. This is the bare-metal form of prototypal inheritance — everything else is built on top of it.

hasOwnProperty: Own vs Inherited

Because lookups walk the chain, "foo" in obj returns true for inherited properties too. When you need to distinguish a property the object actually owns, use Object.hasOwn (or the older hasOwnProperty):

index.js
Output
Click Run to see the output here.

name is on the instance. greet is on the prototype. in finds both; Object.hasOwn only finds the first. This matters whenever you iterate with for...in or serialize an object — you usually want only the own properties.

Don't Monkey-Patch Built-In Prototypes

Because Array.prototype is shared by every array in your program, you could add methods to it:

// Please don't.
Array.prototype.last = function () {
    return this[this.length - 1];
};

[1, 2, 3].last(); // 3

The problem isn't that it doesn't work — it does. The problem is that every library, every dependency, every future version of JavaScript now shares that namespace with you. When Array.prototype.last eventually ships as a real method with slightly different semantics, your code (or someone else's) breaks in subtle ways. The Array.prototype.flatten / Array.prototype.flat saga is the canonical cautionary tale.

Keep helpers as standalone functions:

index.js
Output
Click Run to see the output here.

One less shared surface to collide with.

The Mental Model

Strip everything else away, and prototypes come down to three rules:

  • Every object has a prototype link (possibly null).
  • Property reads walk up that chain; writes don't.
  • class, new, and extends are ways of setting up those chains without typing Object.create yourself.

Keep those three in your head and the behaviour of this, instanceof, method resolution, and inheritance all fall into place.

Next: The Event Loop

Prototypes wrap up the object model. The next chapter moves to something completely different — how JavaScript actually runs your code over time. The event loop is what makes timers, promises, and async/await behave the way they do, and it's the foundation for everything async.

Frequently Asked Questions

What is a prototype in JavaScript?

Every JavaScript object has an internal link to another object called its prototype. When you access a property that isn't on the object itself, JavaScript walks up that link — the prototype chain — looking for it. That chain is how methods defined once get shared across many instances.

What's the difference between __proto__ and prototype?

prototype is a property on constructor functions (and classes). It's the object that will become the prototype of instances created with new. __proto__ (or Object.getPrototypeOf(obj)) is the actual link on an instance pointing to its prototype. So instance.__proto__ === Constructor.prototype.

Are JavaScript classes just syntactic sugar for prototypes?

Mostly, yes. class Foo { bar() {} } puts bar on Foo.prototype, exactly as if you'd written function Foo(){} and Foo.prototype.bar = function(){}. Classes add private fields, stricter semantics, and nicer syntax for extends and super, but the underlying machinery is still prototypes.

Should I add methods to built-in prototypes like Array.prototype?

Almost never. Modifying Array.prototype or Object.prototype affects every array or object in your program, including those from libraries. It can clash with future language additions and break for...in loops. Keep custom helpers in their own functions or modules.

Learn to code with Coddy

GET STARTED