JavaScript Prototypes
Every JavaScript object has an internal link to another object called its prototype. This prototype chain is the mechanism by which JavaScript implements inheritance. When you access a property on an object, JavaScript looks up the prototype chain until it finds the property or reaches null.
The Prototype Chain
Objects inherit properties and methods from their prototype. If a property is not found on the object itself, JavaScript looks at the object's prototype, then the prototype's prototype, and so on until it reaches null.
const animal = {
type: 'Animal',
describe: function() {
return 'I am a ' + this.type;
}
};
const dog = Object.create(animal);
dog.type = 'Dog';
dog.bark = function() { return 'Woof!'; };
// dog -> animal -> Object.prototype -> null
console.log(dog.describe());
console.log(dog.bark());
console.log(dog.toString());
console.log(dog.type);__proto__ vs prototype
The __proto__ property is the actual link to the prototype object on every instance. The prototype property exists only on functions/constructors and is the object that will become the __proto__ of instances created with new.
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return 'Hi, I am ' + this.name;
};
const alice = new Person('Alice');
// .prototype is on the constructor function
console.log(typeof Person.prototype);
// __proto__ is on the instance (links to Person.prototype)
console.log(alice.__proto__ === Person.prototype);
// The method is on the prototype
console.log(alice.greet());
console.log(alice.hasOwnProperty('name'));
console.log(alice.hasOwnProperty('greet'));Object.getPrototypeOf()
Object.getPrototypeOf() is the recommended way to get an object's prototype. It is preferred over the deprecated __proto__ property.
const arr = [1, 2, 3];
const obj = { a: 1 };
const str = new String('hello');
// Get prototype (recommended way)
console.log(Object.getPrototypeOf(arr) === Array.prototype);
console.log(Object.getPrototypeOf(obj) === Object.prototype);
console.log(Object.getPrototypeOf(str) === String.prototype);
// Prototype chain of an array:
// arr -> Array.prototype -> Object.prototype -> null
const arrProto = Object.getPrototypeOf(arr);
const objProto = Object.getPrototypeOf(arrProto);
const nullProto = Object.getPrototypeOf(objProto);
console.log('Array proto is Array.prototype: ' + (arrProto === Array.prototype));
console.log('Next is Object.prototype: ' + (objProto === Object.prototype));
console.log('End of chain: ' + nullProto);Object.create()
Object.create() creates a new object with the specified prototype. This is a clean way to set up inheritance without using constructor functions.
const vehicle = {
type: 'vehicle',
start: function() {
return this.type + ' started';
},
stop: function() {
return this.type + ' stopped';
}
};
// Create car with vehicle as prototype
const car = Object.create(vehicle);
car.type = 'car';
car.drive = function() {
return 'Driving ' + this.type;
};
console.log(car.start());
console.log(car.drive());
console.log(car.stop());
// Object with no prototype
const bare = Object.create(null);
console.log('No prototype: ' + Object.getPrototypeOf(bare));Inheritance via Prototypes and hasOwnProperty()
The hasOwnProperty() method checks if a property belongs directly to an object (not inherited from the prototype chain). This is important when iterating over object properties.
function Shape(color) {
this.color = color;
}
Shape.prototype.getColor = function() {
return this.color;
};
const circle = new Shape('red');
circle.radius = 5;
// Own properties vs inherited
console.log('color own: ' + circle.hasOwnProperty('color'));
console.log('radius own: ' + circle.hasOwnProperty('radius'));
console.log('getColor own: ' + circle.hasOwnProperty('getColor'));
// for...in includes inherited properties
for (const key in circle) {
const own = circle.hasOwnProperty(key) ? '(own)' : '(inherited)';
console.log(key + ' ' + own);
}| Concept | Description |
|---|---|
| __proto__ | Link to the prototype on every object (deprecated) |
| prototype | Property on functions; becomes __proto__ of instances |
| Object.getPrototypeOf() | Standard way to get an object's prototype |
| Object.create(proto) | Create object with a specific prototype |
| hasOwnProperty() | Check if property is directly on the object |
| Prototype chain | Lookup path: object -> proto -> proto -> null |