The pseudoclassical model creates JavaScript objects with constructor functions, new, and prototype links, imitating class-based inheritance. ECMAScript 2015 classes streamlined this approach, but remain syntactic sugar over constructor functions. section 2.2.2 section 2.3
A typical pseudoclassical hierarchy combines several moving parts:
- Define a parent constructor that assigns instance data, such as sender and recipient. section 2.2.2
- Place shared methods on the constructor's prototype so instances reuse the same function. section 2.2.2
- Call the parent constructor with Transaction.call(this, ...) to initialize inherited instance properties. section 2.2.2
- Link the child prototype with Object.create(Parent.prototype), preserving delegated lookup through the prototype chain. section 2.2.2
- Guard against omitted new with new.target or the older this instanceof Constructor check. section 2.2.2
Transaction and HashTransaction
function Transaction(sender, recipient) { this.sender = sender; this.recipient = recipient; }\nTransaction.prototype.displayTransaction = function() {\n return `Transaction from ${this.sender} to ${this.recipient}`;\n};\n\nfunction HashTransaction(sender, recipient) {\n if (!new.target) return new HashTransaction(sender, recipient);\n Transaction.call(this, sender, recipient);\n}\nHashTransaction.prototype = Object.create(Transaction.prototype);\nHashTransaction.prototype.calculateHash = function() { /* ... */ };\n\nconst tx = new HashTransaction('luis@tjoj.com', 'luke@tjoj.com'); section 2.2.2
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] }
Inspect the complete constructor-function pattern, including parent initialization, child methods, prototype linking, and constructor references. section 2.2.2
