Context

This document explores JavaScript’s prototype-based object model, compares it with class-based Object-Oriented Programming (OOP) like Java, and highlights how runtime dynamic lookup differs from static compile-time inheritance.


1. What is a Prototype in JavaScript?

Unlike Java, which uses Classes (blueprints) to instantiate objects, JavaScript uses a Prototype-based model. Every object in JavaScript has an internal link (often exposed via __proto__ or managed via Object.setPrototypeOf) pointing to another object called its prototype.

If you try to access a property or method that doesn’t exist on an object, JavaScript automatically looks up the chain to its prototype to see if it exists there. This process is called delegation.

Mermaid: Prototype Chain

graph LR
    A[Dog Object] -->|__proto__| B[Animal Prototype]
    B -->|__proto__| C[Object.prototype]
    C -->|__proto__| D[null]

2. Similarities to Java Inheritance

On the surface, Java inheritance and JavaScript prototypes share the exact same core goal: Code Reuse.

  1. Method Delegation / Tree Traversal: In both languages, if a method is missing on the current instance/object, the runtime looks up the hierarchy tree to find it.
  2. “Is-A” Relationship: Just like a subclass in Java represents an “is-a” relationship with its superclass, a JavaScript object linked to a prototype shares behavior as if it belongs to that parent type family.

3. Key Differences: Prototype vs. Java Class Inheritance

FeatureJava (Class-Based)JavaScript (Prototype-Based)
MechanismClasses inherit from Classes. Objects are instances of a blueprint.Objects inherit directly from other objects.
Lookup TimingStatic (Compile-time): Checked before the program runs; locked in stone.Dynamic (Runtime): Evaluated live while the code is executing.
MutabilityCannot modify a superclass or add methods to existing compiled classes dynamically at runtime.Can modify prototypes on the fly, and existing objects immediately gain the new behavior.

4. Code Examples

Example 1: Basic Prototype Delegation

// 1. Define a parent object with a shared method
const vehicle = {
  startEngine: function() {
    console.log(`${this.model} engine roaring to life!`);
  }
};
 
// 2. Create a child object and link it to vehicle as its prototype
const myCar = {
  model: "Tesla Model 3"
};
 
Object.setPrototypeOf(myCar, vehicle);
 
// 3. Call a method not directly on myCar
myCar.startEngine(); 
// Output: "Tesla Model 3 engine roaring to life!"
// (JS looked up the chain to `vehicle` and found startEngine)

Example 2: Dynamic Runtime Modification (The Java Contrast)

const gadget = {
  powerOn: function() { console.log("Powering on..."); }
};
 
const myPhone = {};
Object.setPrototypeOf(myPhone, gadget);
 
myPhone.powerOn(); // Output: "Powering on..."
 
// --- LATER, AT RUNTIME ---
// We add a new method to 'gadget' AFTER 'myPhone' was already created
gadget.openApp = function(appName) {
  console.log(`Opening ${appName}...`);
};
 
// myPhone instantly has access to this new method!
myPhone.openApp("Settings"); 
// Output: "Opening Settings..."

Dynamic Pitfall

Because prototype properties can be mutated live, changing a prototype can unexpectedly affect all objects linked to it across your application. Use this flexibility with care!


5. Summary / Mental Model

The Ultimate Takeaway

  • Java Class Inheritance: Think of a concrete building blueprint. Once constructed, the architecture cannot change on the fly.
  • JavaScript Prototypes: Think of a network of objects sharing a family heirloom. If the parent adds something new to their collection, everyone linked to them can immediately use it.