Prototypes
What is a Prototype?
Every JavaScript object has a prototype. A prototype is also an object from which other objects inherit properties and methods. This forms the prototype chain.
Try Prototypes
Code Editor
Console Output
Click "Run" to execute your code...
Example 1: Basic Prototype
// Every object has a __proto__ property
const obj = {};
console.log(obj.__proto__); // Object.prototype
// Function constructor with prototype
function Person(name, age) {
this.name = name;
this.age = age;
}
// Adding method to prototype
Person.prototype.greet = function() {
return `Hello, I'm ${this.name} and I'm ${this.age} years old.`;
};
Person.prototype.species = 'Homo Sapiens';
const person1 = new Person('John', 30);
const person2 = new Person('Jane', 25);
console.log(person1.greet()); // Hello, I'm John and I'm 30 years old.
console.log(person2.greet()); // Hello, I'm Jane and I'm 25 years old.
console.log(person1.species); // Homo Sapiens
// Both share the same prototype
console.log(person1.greet === person2.greet); // true (same function reference)Example 2: Prototype Chain
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
return `${this.name} is eating`;
};
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 Dog-specific method
Dog.prototype.bark = function() {
return `${this.name} says Woof!`;
};
const myDog = new Dog('Buddy', 'Golden Retriever');
console.log(myDog.name); // Buddy
console.log(myDog.breed); // Golden Retriever
console.log(myDog.bark()); // Buddy says Woof!
console.log(myDog.eat()); // Buddy is eating
// Prototype chain: myDog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null
console.log(myDog.__proto__ === Dog.prototype); // true
console.log(myDog.__proto__.__proto__ === Animal.prototype); // true
console.log(myDog.__proto__.__proto__.__proto__ === Object.prototype); // true
// Check inheritance
console.log(myDog instanceof Dog); // true
console.log(myDog instanceof Animal); // true
console.log(myDog instanceof Object); // trueExample 3: Prototype Methods
const obj = { name: 'Test' };
// hasOwnProperty - checks if property exists on object (not prototype)
console.log(obj.hasOwnProperty('name')); // true
console.log(obj.hasOwnProperty('toString')); // false (inherited)
// Object.getPrototypeOf()
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
// Object.setPrototypeOf()
const proto = {
greet: function() {
return `Hello, ${this.name}`;
}
};
const person = { name: 'John' };
Object.setPrototypeOf(person, proto);
console.log(person.greet()); // Hello, John
// isPrototypeOf()
console.log(Object.prototype.isPrototypeOf(obj)); // true
console.log(Array.prototype.isPrototypeOf(obj)); // false
console.log(Array.prototype.isPrototypeOf([])); // true
// Object.create() - creates object with specified prototype
const animal = {
type: 'Animal',
describe: function() {
return `I am a ${this.type}`;
}
};
const cat = Object.create(animal);
cat.type = 'Cat';
cat.name = 'Whiskers';
console.log(cat.describe()); // I am a Cat
console.log(cat.hasOwnProperty('type')); // true
console.log(cat.hasOwnProperty('describe')); // false (inherited)Example 4: ES6 Classes (Syntactic Sugar over Prototypes)
// ES6 class syntax
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
// Methods are added to prototype
greet() {
return `Hi, I'm ${this.name}`;
}
// Static method (not on prototype)
static species() {
return 'Homo Sapiens';
}
}
const john = new Person('John', 30);
console.log(john.greet()); // Hi, I'm John
console.log(Person.species()); // Homo Sapiens
// Methods are on prototype
console.log(john.hasOwnProperty('greet')); // false
console.log(Person.prototype.hasOwnProperty('greet')); // true
// Inheritance with classes
class Employee extends Person {
constructor(name, age, jobTitle) {
super(name, age); // Call parent constructor
this.jobTitle = jobTitle;
}
greet() {
return `${super.greet()}, I'm a ${this.jobTitle}`;
}
work() {
return `${this.name} is working`;
}
}
const emp = new Employee('Jane', 28, 'Developer');
console.log(emp.greet()); // Hi, I'm Jane, I'm a Developer
console.log(emp.work()); // Jane is working
// Still uses prototypes under the hood
console.log(emp instanceof Employee); // true
console.log(emp instanceof Person); // true
console.log(Employee.prototype.__proto__ === Person.prototype); // trueExample 5: Extending Built-in Prototypes
// ⚠️ Warning: Extending built-in prototypes is generally NOT recommended
// But useful to understand how it works
// Adding method to Array prototype
Array.prototype.last = function() {
return this[this.length - 1];
};
const arr = [1, 2, 3, 4, 5];
console.log(arr.last()); // 5
// Adding method to String prototype
String.prototype.capitalize = function() {
return this.charAt(0).toUpperCase() + this.slice(1);
};
console.log('hello'.capitalize()); // Hello
// Adding method to Number prototype
Number.prototype.times = function(callback) {
for (let i = 0; i < this; i++) {
callback(i);
}
};
(3).times(i => console.log(i)); // 0, 1, 2
// Why it's dangerous:
// 1. Can conflict with future JavaScript features
// 2. Can break libraries that iterate over properties
// 3. Pollutes global namespace
// Better approach: Use utility functions
const ArrayUtils = {
last: (arr) => arr[arr.length - 1],
first: (arr) => arr[0]
};
console.log(ArrayUtils.last([1, 2, 3])); // 3Key Points
- Every object has a prototype (accessed via __proto__ or Object.getPrototypeOf())
- Prototypes enable inheritance and method sharing
- Prototype chain: object → prototype → prototype → ... → Object.prototype → null
- Methods on prototype are shared among all instances (memory efficient)
- ES6 classes are syntactic sugar over prototypal inheritance
- Avoid extending built-in prototypes (Array, String, etc.)