liveBook · Manning

Prototype

As explained in The Joy of JavaScript

In JavaScript object creation, the prototype is an object that serves as the shared delegate from which other objects can inherit properties and methods.

A prototype is an object another JavaScript object can delegate to when a property is not found locally. The connection is a link, not a copy: a derived object can add its own properties while retaining access to properties on the linked object. This is differential inheritance. section 2.1 section 2.1.2

Link two objects

const transaction = { sender: 'luis@tjoj.com' }; const payment = Object.create(transaction); payment.funds = 10; payment.sender; // 'luis@tjoj.com' payment.funds; // 10 Object.getPrototypeOf(payment) === transaction; // true The sender property belongs to transaction; funds belongs to payment. Object.create establishes the link without copying sender. section 2.1

Property lookup starts on the receiving object. If the property is absent, JavaScript follows its internal [[Prototype]] reference and repeats the search up the chain, through linked objects to Object.prototype. Thus a method can be called through an object even when that method is defined on its prototype. An unresolved property access yields undefined; trying to call an unresolved method yields a TypeError. The legacy __proto__ property exposes the internal link, but should not be used directly in application code. section 2.1.1

A derived object differentiates itself by adding behavior. For example, a transaction object can supply sender and recipient while a linked object adds calculateHash; another linked object can add funds and addFunds. Lookup proceeds from the most specific object toward its predecessors. Long chains also create coupling: changing an object near the base can affect objects that delegate to it, even at runtime. section 2.1.2 section 1.2

Do not confuse an object's internal [[Prototype]] link with a constructor function's prototype property. A constructor's F.prototype is an object used when creating instances with new; placing a method there lets instances share that method rather than each holding a separate copy. To connect constructor hierarchies, the derived constructor's prototype must be linked to the base constructor's prototype. An incorrect link can leave an expected method unavailable. section 2.2.2

Object.create makes a link explicit; constructor functions can share methods but require careful prototype configuration. Class and extends provide a less boilerplate-heavy way to express an inheritance hierarchy while still setting up prototype-based lookup. These are alternative ways to organize objects, not reasons to treat classes as JavaScript's only object model. section 2.2.2 section 2.3

Listing 2.6 Configuring the prototype chain using the constructor functions pattern
function Transaction(sender, recipient) {  
    this.sender = sender;
    this.recipient = recipient;
}
Transaction.prototype.displayTransaction = function displayTransaction() {
    return `Transaction from ${this.sender} to ${this.recipient}`;
} 
 
function HashTransaction(sender, recipient) {
    if (!new.target) { 
        return new HashTransaction(sender, recipient);
    }
    Transaction.call(this, sender, recipient);      
}
 
HashTransaction.prototype.calculateHash = function calculateHash() { 
    const data = [this.sender, this.recipient].join(''); 
    let hash = 0, i = 0;
    while (i < data.length) {
      hash = ((hash << 5) - hash + data.charCodeAt(i++)) << 0;
    }
    return hash**2;
}
 
HashTransaction.prototype = Object.create(Transaction.prototype);    #1
HashTransaction.prototype.constructor = HashTransaction;             #2
 
const tx = new HashTransaction('luis@tjoj.com', 'luke@tjoj.com');
const tx2 = new HashTransaction('luis@tjoj.com', 'luke@tjoj.com');
Transaction.prototype.isPrototypeOf(tx); // true
tx.calculateHash === tx2.calculateHash;  // true
tx.displayTransaction === tx2.displayTransaction; // true
tx.__proto__.__proto__; 
// Transaction { displayTransaction: [Function: displayTransaction] }

The constructor-function example shows the explicit prototype configuration needed to make a derived transaction share methods from its base. section 2.2.2

How The Joy of JavaScript covers it

How deep it goes
Works through Object.create, property lookup, differential inheritance, and constructor-chain configuration; explicitly defers detailed treatment of property shadowing.
Examples
Models linked transaction objects, shared hash-calculation methods, and constructor-based transaction hierarchies.
What it assumes
Assumes familiarity with JavaScript objects and methods while demonstrating how to establish and inspect a basic prototype link.
What you can do after
Build it from scratch with Object.create or constructor prototypes, and diagnose missing methods by checking prototype-chain links.
How it connects
Connects prototypes to property resolution, differential inheritance, constructor functions, and class-based inheritance.

Also explained in

Compare how 3 books explain prototype →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Joy of JavaScript. The section links point to the parts of the book it draws on.