← Back to Chapters

JavaScript Prototypes

? JavaScript Prototypes

⚡ Quick Overview

In JavaScript, every object has an internal property called [[Prototype]] that points to another object. This link is what allows objects to inherit properties and methods.

Functions also have a public prototype property. When you use the new keyword, the newly created object’s [[Prototype]] is set to that function’s prototype object.

Together, [[Prototype]], the prototype property, and the prototype chain form the core of JavaScript’s object system.

? Key Concepts

  • [[Prototype]]: A hidden internal link from one object to another.
  • Prototype chain: The chain followed when JavaScript looks up a property on an object.
  • prototype on functions: The object that instances created by new will inherit from.
  • __proto__: A legacy accessor on objects that exposes their [[Prototype]].
  • Object.create(): A method to create a new object with a specified prototype.
  • Built-in prototypes: Shared method containers like Array.prototype, Date.prototype, etc.

? Syntax and Theory

You can inspect an object’s prototype using Object.getPrototypeOf() or the legacy __proto__ accessor:

When you access a property on an object, JavaScript:

  1. Checks if the property exists on the object itself.
  2. If not found, moves up to the object referenced by [[Prototype]].
  3. Continues until it reaches null (end of the prototype chain).

Constructor functions use their prototype object as the shared place for methods. Objects created with new will delegate to that prototype for method lookups.

? Use Cases

  • Sharing methods across many instances (e.g., all Person objects share sayHi()).
  • Creating lightweight objects that delegate behavior to a base object via Object.create().
  • Understanding how built-in objects like arrays and dates get their shared methods.
  • Debugging property lookups and avoiding accidental shadowing of prototype properties.

? Code Examples

? Basic object prototype
const obj = {};
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
?️ Prototype chain in action
const parent = {
  greet() {
    console.log("Hello");
  }
};

const child = Object.create(parent);

child.greet(); // "Hello" (inherited from parent)
?️ Constructor function and prototypes
function Person(name) {
  this.name = name;
}

// Shared method for all Person instances
Person.prototype.sayHi = function() {
  console.log("Hi, I'm " + this.name);
};

const user = new Person("Alice");
user.sayHi(); // Hi, I'm Alice
? Overriding and shadowing
const animal = { sound: "Generic" };
const dog = Object.create(animal);

// Own property shadows the prototype property
dog.sound = "Bark";

console.log(dog.sound);    // "Bark" (own property)
console.log(animal.sound); // "Generic" (unchanged)
prototype vs __proto__
function Car() {}

const car = new Car();

// car.[[Prototype]] === Car.prototype
console.log(car.__proto__ === Car.prototype); // true
? Using Object.create()
const base = { type: "base" };

const derived = Object.create(base);

console.log(derived.type);                          // "base"
console.log(Object.getPrototypeOf(derived) === base); // true
? Built-in prototypes
const arr = [1, 2, 3];

// arr.[[Prototype]] is Array.prototype in most environments
console.log(arr.__proto__ === Array.prototype); // true

// You can use built-in methods from the prototype
console.log(arr.map((x) => x * 2)); // [2, 4, 6]

? Live Output & Explanation

? Following the prototype chain

Consider this code:

? View Code Example
const parent = { greet() { console.log("Hello"); } };
const child = Object.create(parent);

child.greet();

Step by step:

  • child does not have its own greet property.
  • JavaScript follows child.[[Prototype]], which points to parent.
  • It finds greet on parent and calls it.
  • The console prints: Hello.

This is the prototype chain in action: child → parent → Object.prototype → null.

? Tips & Best Practices

  • Use Object.create() when you want fine-grained control over an object’s prototype.
  • Place shared methods on Function.prototype (like Person.prototype.sayHi) instead of inside the constructor.
  • Avoid heavily modifying built-in prototypes (like Array.prototype) in real projects.
  • Understand the difference between prototype (on functions) and __proto__ (on objects).
  • Prefer Object.getPrototypeOf() over __proto__ in modern code.

? Try It Yourself

  • Create a constructor Book with a prototype method describe() that logs "Title by Author".
  • Use Object.create() to create an object that inherits from another and test property lookup on both the child and parent.
  • Override an inherited property (like sound or type) on the child object and observe how shadowing works.
  • Inspect prototypes using Object.getPrototypeOf() and draw the prototype chain you see in the console.
  • Rewrite one of the examples using ES6 class syntax and relate it back to prototypes.