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


