JavaScript 29 🧬 Prototype
A prototype is a mechanism that allows you to add properties and methods to objects. Every JavaScript function has a prototype property, which refers to an object known as the prototype object — a template from which all instances of the function’s objects are created.
A Quick Look at the Examples
// 1. Constructor function
function Person(name, age) {
this.name = name;
this.age = age;
}
// 2. Adding method to prototype
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};
// 3. Creating instances
const person1 = new Person('Alice', 30);
const person2 = new Person('Bob', 25);
person1.greet(); // "Hello, my name is Alice and I am 30 years old."
person2.greet(); // "Hello, my name is Bob and I am 25 years old."
// 4. Accessing the prototype
console.log(Object.getPrototypeOf(person1) === Person.prototype); // true
console.log(person1.__proto__ === Person.prototype); // true
// 5. Extending built-in prototypes
Array.prototype.sum = function() {
return this.reduce((acc, num) => acc + num, 0);
};
const numbers = [1, 2, 3, 4];
console.log(numbers.sum()); // 10
a. What is the Prototype?
A prototype is a mechanism that allows you to add properties and methods to objects. Every JavaScript function has a prototype property that refers to an object known as the prototype object. This prototype object serves as a template from which all instances of the function’s objects are created.
How Prototypes Work
| Step | Description |
|---|---|
| 1. Function Declaration | When you declare a function, it automatically gets a prototype property |
| 2. Creating Objects | When you create an object with new, it inherits properties/methods from the constructor’s prototype |
| 3. Inheritance | The new object has a hidden [[Prototype]] property that points to the constructor’s prototype object |
Visual:
┌─────────────────────────────┐
│ Person (function) │
│ ├── prototype ────────┐ │
│ └── ... │ │
└────────────────────────┼────┘
│
▼
┌──────────────────────┐
│ Person.prototype │
│ ├── greet: function │
│ └── constructor ────┼──→ Person
└──────────┬───────────┘
│
│ [[Prototype]]
┌──────────┴───────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ person1 │ │ person2 │
│ ├── name │ │ ├── name │
│ └── age │ │ └── age │
└──────────────┘ └──────────────┘
b. Accessing and Modifying Prototypes
Prototype Chain
When you access a property or method on an object, JavaScript:
- First looks for it on the object itself
- If not found, looks up the prototype chain
- Continues until it finds the property/method or reaches the end (i.e.,
null)
const person1 = new Person('Alice', 30);
// Looking up "name" — found on person1
console.log(person1.name); // "Alice"
// Looking up "greet" — NOT on person1, found on Person.prototype
person1.greet(); // Works!
// Looking up "toString" — NOT on person1, NOT on Person.prototype,
// found on Object.prototype (further up the chain)
console.log(person1.toString()); // "[object Object]"
// Looking up "nonexistent" — reaches null, returns undefined
console.log(person1.nonexistent); // undefined
Visual chain:
person1
│
├── name: "Alice"
├── age: 30
│
└── [[Prototype]] ──→ Person.prototype
│
├── greet: function
├── constructor: Person
│
└── [[Prototype]] ──→ Object.prototype
│
├── toString: function
├── hasOwnProperty: function
└── [[Prototype]] ──→ null
Efficiency
By defining methods on the prototype, you save memory — the method is shared across all instances rather than being duplicated for each instance.
// ❌ BAD: Each instance gets its own copy of greet
function PersonBad(name) {
this.name = name;
this.greet = function() { console.log("Hi " + this.name); };
}
// Every new PersonBad() creates a NEW function for greet — memory waste!
// ✅ GOOD: All instances share the same greet method
function PersonGood(name) {
this.name = name;
}
PersonGood.prototype.greet = function() { console.log("Hi " + this.name); };
// Only ONE greet function exists — shared by all instances
Inheritance
Prototypes allow for inheritance — objects can inherit properties and methods from other objects.
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a sound.`);
};
function Dog(name, breed) {
Animal.call(this, name); // Call parent constructor
this.breed = breed;
}
// Set up inheritance
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// Add method specific to Dog
Dog.prototype.bark = function() {
console.log(`${this.name} barks!`);
};
const dog = new Dog('Rex', 'Labrador');
dog.speak(); // "Rex makes a sound." (inherited from Animal)
dog.bark(); // "Rex barks!" (own method)
Accessing the Prototype
Two ways to access an object’s prototype:
| Method | Description | Status |
|---|---|---|
Object.getPrototypeOf(obj) | Standard method | ✅ Recommended |
obj.__proto__ | Legacy accessor | ⚠️ Deprecated |
console.log(Object.getPrototypeOf(person1) === Person.prototype); // true
console.log(person1.__proto__ === Person.prototype); // true
// Also:
console.log(Person.prototype.isPrototypeOf(person1)); // true
console.log(person1 instanceof Person); // true
Modifying the Prototype
You can add, modify, or delete properties and methods on a prototype object at any time.
function Person(name) {
this.name = name;
}
const person = new Person('Alice');
// Add method AFTER instance creation — still works!
Person.prototype.greet = function() {
console.log(`Hello, ${this.name}`);
};
person.greet(); // "Hello, Alice" — finds it via prototype chain
// Modify method
Person.prototype.greet = function() {
console.log(`Hey there, ${this.name}!`);
};
person.greet(); // "Hey there, Alice!"
// Delete method
delete Person.prototype.greet;
// person.greet(); // ❌ TypeError: person.greet is not a function
⚠️ Caution: Modifying built-in objects’ prototypes (like Array, String, Object) can lead to unexpected behavior and is generally discouraged in production code.
// ⚠️ DANGEROUS: Modifying built-in prototypes
Array.prototype.sum = function() {
return this.reduce((acc, num) => acc + num, 0);
};
const numbers = [1, 2, 3, 4];
console.log(numbers.sum()); // 10
// BUT: This can break other code!
for (let key in numbers) {
console.log(key); // "0", "1", "2", "3", "sum" ← "sum" shows up!
}
Why it’s risky:
- Other libraries may use the same name
for...inloops will iterate over your added methods- Future JavaScript versions may add conflicting methods
c. Prototype Examples
Example 1: Constructor Function
function Person(name, age) {
this.name = name;
this.age = age;
}
Creates a constructor that sets name and age on each instance.
Example 2: Adding a Method to the Prototype
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};
Adds a greet method shared by all instances.
Example 3: Creating Objects Using the Constructor
const person1 = new Person('Alice', 30);
const person2 = new Person('Bob', 25);
Each instance has its own name and age, but shares greet.
Example 4: Using the Greet Method
person1.greet(); // "Hello, my name is Alice and I am 30 years old."
person2.greet(); // "Hello, my name is Bob and I am 25 years old."
JavaScript finds greet on Person.prototype.
Example 5: Accessing the Prototype
console.log(person1.__proto__ === Person.prototype); // true
console.log(Object.getPrototypeOf(person1) === Person.prototype); // true
Both access the same prototype object.
Example 6: Adding a Method to the Array Prototype
Array.prototype.sum = function() {
return this.reduce((acc, num) => acc + num, 0);
};
const numbers = [1, 2, 3, 4];
console.log(numbers.sum()); // 10
Extends all arrays with a sum method — ⚠️ use with caution!
Complete Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Prototype</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #f8f9fa;
color: #333;
line-height: 1.6;
}
h1 { color: #007bff; border-bottom: 3px solid #007bff; padding-bottom: 10px; }
h2 { color: #28a745; border-left: 4px solid #28a745; padding-left: 15px; margin-top: 30px; }
.demo-box {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin: 15px 0;
}
pre {
background: #1e1e1e;
color: #d4d4d4;
padding: 15px;
border-radius: 8px;
overflow-x: auto;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
line-height: 1.8;
}
.keyword { color: #569cd6; }
.string { color: #ce9178; }
.number { color: #b5cea8; }
.function { color: #dcdcaa; }
.comment { color: #6a9955; }
.boolean { color: #569cd6; }
#output {
background: #e9ecef;
padding: 15px;
border-radius: 8px;
margin-top: 15px;
min-height: 40px;
font-family: 'Courier New', monospace;
font-size: 0.85rem;
border-left: 4px solid #007bff;
white-space: pre-wrap;
}
table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
th { background: #007bff; color: white; }
tr:nth-child(even) { background: #f8f9fa; }
.btn {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 6px;
font-size: 1em;
font-weight: bold;
cursor: pointer;
margin: 5px;
transition: all 0.3s;
}
.btn:hover {
background: #0056b3;
transform: translateY(-2px);
}
.btn-success { background: #28a745; }
.btn-success:hover { background: #1e7e34; }
.chain-viz {
font-family: 'Courier New', monospace;
font-size: 0.85rem;
background: #1e1e1e;
color: #d4d4d4;
padding: 20px;
border-radius: 8px;
margin: 15px 0;
white-space: pre;
overflow-x: auto;
line-height: 1.8;
}
.proto-key { color: #569cd6; }
.proto-value { color: #ce9178; }
.proto-method { color: #dcdcaa; }
.proto-highlight { color: #4ec9b0; font-weight: bold; }
</style>
</head>
<body>
<h1>Prototype</h1>
<div class="demo-box">
<h2>1. Constructor Function and Prototype</h2>
<pre>
<span class="keyword">function</span> <span class="function">Person</span>(name, age) {
<span class="keyword">this</span>.name = name;
<span class="keyword">this</span>.age = age;
}
<span class="function">Person</span>.prototype.greet = <span class="keyword">function</span>() {
console.log(<span class="string">`Hello, my name is ${this.name} and I am ${this.age} years old.`</span>);
};
<span class="keyword">const</span> person1 = <span class="keyword">new</span> <span class="function">Person</span>(<span class="string">'Alice'</span>, <span class="number">30</span>);
<span class="keyword">const</span> person2 = <span class="keyword">new</span> <span class="function">Person</span>(<span class="string">'Bob'</span>, <span class="number">25</span>);
person1.<span class="function">greet</span>();
person2.<span class="function">greet</span>();
</pre>
</div>
<div class="demo-box">
<h2>2. Prototype Chain Visualization</h2>
<div class="chain-viz">
<span class="proto-highlight">person1</span>
├── name: <span class="proto-value">"Alice"</span>
├── age: <span class="proto-value">30</span>
│
└── [[Prototype]] ──→ <span class="proto-highlight">Person.prototype</span>
├── greet: <span class="proto-method">function</span>
├── constructor: <span class="proto-method">Person</span>
│
└── [[Prototype]] ──→ <span class="proto-highlight">Object.prototype</span>
├── toString: <span class="proto-method">function</span>
├── hasOwnProperty: <span class="proto-method">function</span>
├── valueOf: <span class="proto-method">function</span>
│
└── [[Prototype]] ──→ <span class="proto-value">null</span>
</div>
</div>
<div class="demo-box">
<h2>3. Memory Efficiency — Shared Methods</h2>
<pre>
<span class="comment">// ❌ BAD: Each instance gets its own copy</span>
<span class="keyword">function</span> <span class="function">PersonBad</span>(name) {
<span class="keyword">this</span>.name = name;
<span class="keyword">this</span>.greet = <span class="keyword">function</span>() { console.log(<span class="string">"Hi "</span> + <span class="keyword">this</span>.name); };
}
<span class="comment">// Every new PersonBad() creates a NEW function</span>
<span class="comment">// ✅ GOOD: All instances share the method</span>
<span class="keyword">function</span> <span class="function">PersonGood</span>(name) {
<span class="keyword">this</span>.name = name;
}
<span class="function">PersonGood</span>.prototype.greet = <span class="keyword">function</span>() { console.log(<span class="string">"Hi "</span> + <span class="keyword">this</span>.name); };
<span class="comment">// Only ONE greet function exists — shared by all instances</span>
</pre>
</div>
<div class="demo-box">
<h2>4. Prototype Methods Comparison</h2>
<table>
<tr>
<th>Method</th>
<th>Description</th>
<th>Recommended?</th>
</tr>
<tr>
<td><code>Object.getPrototypeOf(obj)</code></td>
<td>Standard way to get prototype</td>
<td>✅ Yes</td>
</tr>
<tr>
<td><code>obj.__proto__</code></td>
<td>Legacy accessor</td>
<td>⚠️ Deprecated</td>
</tr>
<tr>
<td><code>Person.prototype.isPrototypeOf(obj)</code></td>
<td>Check if prototype is in chain</td>
<td>✅ Yes</td>
</tr>
<tr>
<td><code>obj instanceof Person</code></td>
<td>Check if object is instance</td>
<td>✅ Yes</td>
</tr>
<tr>
<td><code>obj.hasOwnProperty(key)</code></td>
<td>Check if property is on object itself</td>
<td>✅ Yes</td>
</tr>
</table>
</div>
<div class="demo-box">
<h2>5. Interactive: Prototype Explorer</h2>
<div style="margin: 10px 0;">
<button class="btn" onclick="showPersonProto()">Show person1.prototype</button>
<button class="btn" onclick="showOwnProps()">Show own properties</button>
<button class="btn btn-success" onclick="showProtoChain()">Show full chain</button>
<button class="btn" onclick="addProtoMethod()">Add method to prototype</button>
<button class="btn" onclick="checkProtoEquality()">Check prototype equality</button>
</div>
<div id="protoOutput" style="background: #1e1e1e; color: #d4d4d4; padding: 15px; border-radius: 8px; font-family: 'Courier New', monospace; font-size: 0.85rem; min-height: 100px; white-space: pre-wrap; margin-top: 10px;"></div>
</div>
<div class="demo-box">
<h2>6. Live Output — All Examples</h2>
<div id="output">Loading...</div>
</div>
<script>
// ============================================
// Prototype — Live Demo
// ============================================
let results = [];
// 1. Constructor + prototype method
results.push('📌 Constructor Function + Prototype Method:\n');
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
};
const person1 = new Person('Alice', 30);
const person2 = new Person('Bob', 25);
results.push(' person1.greet() → ' + person1.greet());
results.push(' person2.greet() → ' + person2.greet());
results.push('');
// 2. Prototype equality
results.push('📌 Prototype Equality:\n');
results.push(' Object.getPrototypeOf(person1) === Person.prototype → ' +
(Object.getPrototypeOf(person1) === Person.prototype));
results.push(' person1.__proto__ === Person.prototype → ' +
(person1.__proto__ === Person.prototype));
results.push(' Person.prototype.isPrototypeOf(person1) → ' +
Person.prototype.isPrototypeOf(person1));
results.push(' person1 instanceof Person → ' + (person1 instanceof Person));
results.push('');
// 3. Own vs inherited properties
results.push('📌 Own vs Inherited Properties:\n');
results.push(' person1.hasOwnProperty("name") → ' + person1.hasOwnProperty('name'));
results.push(' person1.hasOwnProperty("age") → ' + person1.hasOwnProperty('age'));
results.push(' person1.hasOwnProperty("greet") → ' + person1.hasOwnProperty('greet'));
results.push(' → "greet" is inherited, not own!');
results.push('');
// 4. Prototype chain
results.push('📌 Prototype Chain:\n');
function getProtoChain(obj) {
const chain = [];
let current = obj;
while (current !== null) {
const name = current.constructor?.name || 'Object';
chain.push(name + '.prototype');
current = Object.getPrototypeOf(current);
}
chain.push('null');
return chain;
}
results.push(' person1 chain: ' + getProtoChain(person1).join(' → '));
results.push('');
// 5. Shared methods (memory efficiency)
results.push('📌 Shared Methods (Memory Efficiency):\n');
function PersonBad(name) {
this.name = name;
this.greet = function() { return "Hi " + this.name; };
}
function PersonGood(name) {
this.name = name;
}
PersonGood.prototype.greet = function() { return "Hi " + this.name; };
const bad1 = new PersonBad('A');
const bad2 = new PersonBad('B');
const good1 = new PersonGood('A');
const good2 = new PersonGood('B');
results.push(' BAD: bad1.greet === bad2.greet → ' + (bad1.greet === bad2.greet));
results.push(' GOOD: good1.greet === good2.greet → ' + (good1.greet === good2.greet));
results.push(' → Prototype methods are SHARED!');
results.push('');
// 6. Modifying prototype after instance creation
results.push('📌 Modifying Prototype After Instance Creation:\n');
const person3 = new Person('Charlie', 40);
results.push(' Before: person3.hasOwnProperty("sayBye") → ' + person3.hasOwnProperty('sayBye'));
Person.prototype.sayBye = function() {
return `Goodbye from ${this.name}`;
};
results.push(' After adding sayBye to prototype:');
results.push(' person3.sayBye() → ' + person3.sayBye());
results.push(' → Instances automatically get new methods!');
results.push('');
// 7. Inheritance example
results.push('📌 Prototype Inheritance:\n');
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
return `${this.name} makes a sound.`;
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
return `${this.name} barks!`;
};
const dog = new Dog('Rex', 'Labrador');
results.push(' dog.speak() → ' + dog.speak() + ' (inherited)');
results.push(' dog.bark() → ' + dog.bark() + ' (own)');
results.push(' dog.breed → ' + dog.breed);
results.push(' dog instanceof Dog → ' + (dog instanceof Dog));
results.push(' dog instanceof Animal → ' + (dog instanceof Animal));
results.push(' → Dog inherits from Animal!');
results.push('');
// 8. Extending Array prototype (with caution note)
results.push('📌 Extending Array Prototype (⚠️ caution):\n');
if (!Array.prototype.sum) {
Array.prototype.sum = function() {
return this.reduce((acc, num) => acc + num, 0);
};
}
const numbers = [1, 2, 3, 4];
results.push(' [1, 2, 3, 4].sum() → ' + numbers.sum());
results.push(' ⚠️ Warning: Modifying built-in prototypes can cause issues!');
results.push(' → for...in loops would iterate "sum"');
results.push(' → Other libraries may use the same name');
results.push(' → Better: create a custom utility function');
results.push('');
// 9. Class syntax (modern equivalent)
results.push('📌 ES6 Class (Modern Equivalent):\n');
class PersonClass {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, I'm ${this.name}`;
}
}
const classPerson = new PersonClass('Dave', 35);
results.push(' classPerson.greet() → ' + classPerson.greet());
results.push(' → Classes are syntactic sugar over prototypes!');
results.push(' typeof PersonClass → ' + typeof PersonClass);
results.push(' classPerson.hasOwnProperty("greet") → ' + classPerson.hasOwnProperty('greet'));
results.push(' → greet is still on the prototype!');
results.push('');
// 10. Practical: Property lookup
results.push('📌 Practical: Property Lookup Order:\n');
const lookupObj = new Person('Eve', 28);
lookupObj.city = 'NYC'; // Own property
results.push(' lookupObj.name → ' + lookupObj.name + ' (own)');
results.push(' lookupObj.city → ' + lookupObj.city + ' (own)');
results.push(' lookupObj.greet → ' + typeof lookupObj.greet + ' (inherited)');
results.push(' lookupObj.toString → ' + typeof lookupObj.toString + ' (from Object.prototype)');
results.push(' lookupObj.unknown → ' + lookupObj.unknown + ' (not found)');
document.getElementById('output').textContent = results.join('\n');
// ============================================
// Interactive Prototype Explorer
// ============================================
function showPersonProto() {
const output = document.getElementById('protoOutput');
const proto = Object.getPrototypeOf(person1);
let html = '<span style="color: #569cd6;">Object.getPrototypeOf(person1):</span>\n';
html += '{\n';
for (let key of Object.getOwnPropertyNames(proto)) {
if (key === 'constructor') {
html += ` <span style="color: #dcdcaa;">${key}</span>: <span style="color: #569cd6;">[Function: Person]</span>,\n`;
} else {
html += ` <span style="color: #dcdcaa;">${key}</span>: <span style="color: #569cd6;">[Function]</span>,\n`;
}
}
html += '}';
output.innerHTML = html;
}
function showOwnProps() {
const output = document.getElementById('protoOutput');
const ownProps = Object.keys(person1);
let html = '<span style="color: #569cd6;">Object.keys(person1):</span>\n';
html += '[\n';
ownProps.forEach((key, i) => {
const comma = i < ownProps.length - 1 ? ',' : '';
html += ` <span style="color: #ce9178;">"${key}"</span>: <span style="color: #b5cea8;">"${person1[key]}"</span>${comma}\n`;
});
html += ']\n';
html += '\n<span style="color: #4ec9b0;">→ Only own properties, no prototype methods!</span>';
output.innerHTML = html;
}
function showProtoChain() {
const output = document.getElementById('protoOutput');
let current = person1;
let html = '<span style="color: #569cd6;">Prototype Chain:</span>\n\n';
let depth = 0;
while (current !== null) {
const indent = ' '.repeat(depth);
const name = current.constructor?.name || 'Object';
const props = Object.getOwnPropertyNames(current).filter(p => p !== 'constructor');
html += `${indent}<span style="color: #4ec9b0;">${name}${current === person1 ? ' (instance)' : '.prototype'}</span>\n`;
if (props.length > 0 && depth > 0) {
props.slice(0, 3).forEach(prop => {
html += `${indent} <span style="color: #dcdcaa;">${prop}</span>\n`;
});
if (props.length > 3) {
html += `${indent} <span style="color: #6a9955;">... and ${props.length - 3} more</span>\n`;
}
}
current = Object.getPrototypeOf(current);
depth++;
}
html += '\n<span style="color: #ce9178;">null</span>';
output.innerHTML = html;
}
function addProtoMethod() {
const output = document.getElementById('protoOutput');
if (!Person.prototype.introduce) {
Person.prototype.introduce = function() {
return `I'm ${this.name}, ${this.age} years old.`;
};
output.innerHTML = `<span style="color: #4ec9b0;">✅ Added introduce() to Person.prototype</span>\n\n` +
`<span style="color: #569cd6;">Before:</span> person1.introduce → ${typeof person1.introduce === 'undefined' ? 'undefined' : 'function'}\n\n` +
`<span style="color: #569cd6;">After:</span>\n` +
` person1.introduce() → "${person1.introduce()}"\n` +
` person2.introduce() → "${person2.introduce()}"\n\n` +
`<span style="color: #4ec9b0;">→ All instances get the new method!</span>`;
} else {
output.innerHTML = `<span style="color: #4ec9b0;">introduce() already exists on prototype</span>\n\n` +
`person1.introduce() → "${person1.introduce()}"`;
}
}
function checkProtoEquality() {
const output = document.getElementById('protoOutput');
output.innerHTML =
`<span style="color: #569cd6;">Prototype Equality Checks:</span>\n\n` +
` Object.getPrototypeOf(person1) === Person.prototype\n` +
` → <span style="color: #4ec9b0;">${Object.getPrototypeOf(person1) === Person.prototype}</span>\n\n` +
` person1.__proto__ === Person.prototype\n` +
` → <span style="color: #4ec9b0;">${person1.__proto__ === Person.prototype}</span>\n\n` +
` Person.prototype.isPrototypeOf(person1)\n` +
` → <span style="color: #4ec9b0;">${Person.prototype.isPrototypeOf(person1)}</span>\n\n` +
` person1 instanceof Person\n` +
` → <span style="color: #4ec9b0;">${person1 instanceof Person}</span>\n\n` +
` person1 instanceof Object\n` +
` → <span style="color: #4ec9b0;">${person1 instanceof Object}</span>`;
}
// Initialize
showProtoChain();
</script>
</body>
</html>
Quick Reference
What is a Prototype?
| Aspect | Description |
|---|---|
| Definition | Mechanism for adding properties/methods to objects |
| Where it lives | Every function has a prototype property |
| Shared by | All instances created with new |
| Enables | Inheritance, memory efficiency, method reuse |
Prototype Chain
instance
│
└── [[Prototype]] ──→ Constructor.prototype
│
└── [[Prototype]] ──→ Object.prototype
│
└── [[Prototype]] ──→ null
Lookup order:
- Object itself
- Its prototype
- Prototype’s prototype
- … until
null
Accessing the Prototype
| Method | Description | Status |
|---|---|---|
Object.getPrototypeOf(obj) | Standard method | ✅ Recommended |
obj.__proto__ | Legacy accessor | ⚠️ Deprecated |
Constructor.prototype | Constructor’s prototype | ✅ Recommended |
obj instanceof Constructor | Check instance | ✅ Recommended |
Constructor.prototype.isPrototypeOf(obj) | Check chain | ✅ Recommended |
Prototype vs Class (Modern)
// Prototype style (classic)
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `Hi, I'm ${this.name}`;
};
// Class style (modern — same underlying mechanism)
class PersonClass {
constructor(name) {
this.name = name;
}
greet() {
return `Hi, I'm ${this.name}`;
}
}
Both produce the same result — classes are just syntactic sugar over prototypes!
Best Practices
✅ Do This:
// Define methods on the prototype for memory efficiency
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `Hi, ${this.name}`;
};
// Use Object.create for inheritance
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// Use Object.getPrototypeOf() (not __proto__)
const proto = Object.getPrototypeOf(obj);
// Use classes for modern OOP
class Person {
constructor(name) { this.name = name; }
greet() { return `Hi, ${this.name}`; }
}
// Check own vs inherited
if (obj.hasOwnProperty('key')) { }
❌ Don’t Do This:
// Don't duplicate methods on every instance
function Person(name) {
this.name = name;
this.greet = function() { }; // ❌ Creates new function per instance!
}
// Don't use __proto__ in production
obj.__proto__; // ❌ Deprecated — use Object.getPrototypeOf()
// Don't modify built-in prototypes
Array.prototype.myMethod = function() { }; // ⚠️ Dangerous!
// Don't forget to reset constructor after inheritance
Dog.prototype = Object.create(Animal.prototype);
// Dog.prototype.constructor = Dog; // ❌ Missing — constructor points to Animal!
// Don't confuse prototype with instance
Person.greet; // ❌ Constructor doesn't have greet
Person.prototype.greet; // ✅ Prototype has greet
person1.greet; // ✅ Instance inherits greet
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
| Modifying built-ins | Breaks other code | Avoid; use utilities |
__proto__ in code | Deprecated | Use Object.getPrototypeOf() |
Forgetting constructor | Wrong constructor reference | Reset after inheritance |
| Shared mutable state | All instances affected | Keep data on instance, not prototype |
| Modifying prototype during iteration | Unpredictable | Don’t |
Real-World Example
// Custom error class using prototypes
function ValidationError(message, field) {
Error.call(this, message);
this.name = 'ValidationError';
this.field = field;
this.message = message;
}
ValidationError.prototype = Object.create(Error.prototype);
ValidationError.prototype.constructor = ValidationError;
ValidationError.prototype.toString = function() {
return `${this.name}: ${this.message} (field: ${this.field})`;
};
try {
throw new ValidationError('Invalid email', 'email');
} catch (error) {
console.log(error.toString());
console.log(error instanceof ValidationError); // true
console.log(error instanceof Error); // true
}
Pro Tip: Prototypes are the foundation of JavaScript’s object model. Understanding them helps you:
- Debug inheritance issues — know what’s on the instance vs prototype
- Optimize memory — define methods on prototypes, not instances
- Understand classes — they’re just prototype-based under the hood
- Use
Object.create()for clean inheritance - Avoid modifying built-in prototypes — it can break other code
Rule of thumb: Data on the instance, methods on the prototype. Use ES6 classes for modern code — they’re cleaner and do the same thing!
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!