prototypes is an important JavaScript topic because it shows up in real projects, debugging sessions, and interviews. Learn the meaning first, then connect it to a small working example so the rule does not stay abstract.
Focus on what problem prototypes solves, where developers usually make mistakes, and how to verify the result with output, behavior, or a small test.
A strong understanding of prototypes should include syntax, behavior, one realistic use case, one failure case, and one quick way to check your work.
JavaScript Prototypes Prototype Chain should be studied as a practical JavaScript lesson, not as a label. Start by naming the input, the rule that changes the input, and the result a learner should be able to predict after reading the page.
In the javascript > prototypes page, the notes should connect the definition with a working scenario, a mistake that beginners actually make, and the exact check that proves the fix. That makes the topic useful for coding, debugging, and interview revision.
JavaScript is a prototype-based language. This means objects can inherit properties and methods from other objects. Instead of copying every method into every object, JavaScript lets objects share behavior through a prototype chain.
Modern JavaScript has class syntax, but classes still use prototypes internally. Understanding prototypes helps you understand objects, inheritance, methods, this, new, class, and many interview questions much more clearly.
When you access a property on an object, JavaScript first checks the object itself. If the property is not found, JavaScript looks at the object's prototype. If it is not found there, JavaScript continues up the prototype chain until it finds the property or reaches null.
The object user does not define toString, but it can still access it because ordinary objects inherit from Object.prototype.
const user = {
name: 'Asha'
};
console.log(user.name); // Asha - found on user
console.log(user.toString); // found on Object.prototype
// JavaScript looks like this:
// user -> Object.prototype -> null
This topic has confusing names, so separate these two ideas:
function Student(name) {
this.name = name;
}
const student = new Student('Riya');
console.log(Student.prototype); // object used for Student instances
console.log(Object.getPrototypeOf(student) === Student.prototype); // true
Before ES6 classes, constructor functions were the common way to create many similar objects. A constructor function is called with new. Methods should usually be placed on the constructor's prototype so all instances can share one method instead of creating a new function for every instance.
The two objects have different data, but they share the same introduce() method through Student.prototype.
function Student(name, course) {
this.name = name;
this.course = course;
}
Student.prototype.introduce = function() {
return `${this.name} is learning ${this.course}.`;
};
const student1 = new Student('Aman', 'JavaScript');
const student2 = new Student('Neha', 'React');
console.log(student1.introduce()); // Aman is learning JavaScript.
console.log(student2.introduce()); // Neha is learning React.
console.log(student1.introduce === student2.introduce); // true
Properties placed directly on an instance belong only to that object. Properties placed on the prototype are shared through inheritance.
function Student(name) {
this.name = name; // own property
}
Student.prototype.school = 'Tutorials Logic'; // shared prototype property
const student1 = new Student('Rohit');
const student2 = new Student('Kavya');
student1.age = 22; // only student1 has age
console.log(student1.name); // Rohit
console.log(student1.school); // Tutorials Logic
console.log(student2.school); // Tutorials Logic
console.log(student2.age); // undefined
A prototype can also have its own prototype. This creates a chain. JavaScript walks this chain during property lookup.
Here, dog inherits from Dog.prototype, and Dog.prototype inherits from Animal.prototype. If JavaScript cannot find speak() on the dog itself or on Dog.prototype, it finds it on Animal.prototype.
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');
console.log(dog.bark()); // Rex barks.
console.log(dog.speak()); // Rex makes a sound.
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
Use Object.getPrototypeOf() to inspect an object's prototype. Use Object.setPrototypeOf() rarely, because changing prototypes after objects are created can hurt performance and make code harder to reason about.
in checks the object and its prototype chain. Object.hasOwn() checks only the object's own properties.
const user = { name: 'Meera' };
console.log(Object.getPrototypeOf(user) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype)); // null
console.log('toString' in user); // true, inherited
console.log(Object.hasOwn(user, 'toString')); // false
console.log(Object.hasOwn(user, 'name')); // true
Object.create() creates a new object with a specific prototype. It is a direct way to build prototype inheritance without using a constructor function.
const userMethods = {
greet() {
return `Hello, ${this.name}`;
}
};
const user = Object.create(userMethods);
user.name = 'Anaya';
console.log(user.greet()); // Hello, Anaya
console.log(Object.getPrototypeOf(user) === userMethods); // true
Sometimes you may want a plain dictionary object with no inherited properties. Object.create(null) creates an object whose prototype is null. This can be useful for maps or lookup tables, though Map is often better in modern JavaScript.
const dictionary = Object.create(null);
dictionary.javascript = 'A programming language';
dictionary.prototype = 'An inheritance object';
console.log(dictionary.javascript);
console.log(dictionary.toString); // undefined
console.log(Object.getPrototypeOf(dictionary)); // null
The class syntax is the modern way to write constructor-style object code. It is easier to read, but instance methods are still stored on the class prototype.
The title property belongs to the instance. The getTitle() method belongs to Course.prototype and is shared by all Course instances.
class Course {
constructor(title) {
this.title = title;
}
getTitle() {
return this.title;
}
}
const jsCourse = new Course('JavaScript');
console.log(jsCourse.getTitle()); // JavaScript
console.log(Object.getPrototypeOf(jsCourse) === Course.prototype); // true
console.log(Course.prototype.getTitle === jsCourse.getTitle); // true
When a class extends another class, JavaScript sets up a prototype chain between the child prototype and the parent prototype.
class Vehicle {
constructor(make) {
this.make = make;
}
describe() {
return `Vehicle: ${this.make}`;
}
}
class Car extends Vehicle {
constructor(make, model) {
super(make);
this.model = model;
}
details() {
return `${this.describe()} ${this.model}`;
}
}
const car = new Car('Toyota', 'Camry');
console.log(car.details()); // Vehicle: Toyota Camry
console.log(Object.getPrototypeOf(Car.prototype) === Vehicle.prototype); // true
Classes also have a prototype relationship at the constructor level. This is why static methods can be inherited by child classes.
Instance methods are found through Formatter.prototype. Static methods are found through the constructor function itself.
class Tool {
static category() {
return 'Developer Tool';
}
}
class Formatter extends Tool {}
console.log(Formatter.category()); // Developer Tool
console.log(Object.getPrototypeOf(Formatter) === Tool); // true
If an object has its own property with the same name as a prototype property, the own property wins. This is called shadowing.
const defaults = {
theme: 'light'
};
const settings = Object.create(defaults);
console.log(settings.theme); // light - inherited
settings.theme = 'dark';
console.log(settings.theme); // dark - own property shadows prototype
console.log(Object.hasOwn(settings, 'theme')); // true
Prototype properties are shared. That is good for methods, but dangerous for mutable data such as arrays and objects. Put instance-specific data inside the constructor instead.
function TodoList() {}
// Bad: every instance shares the same array.
TodoList.prototype.items = [];
const personal = new TodoList();
const work = new TodoList();
personal.items.push('Buy milk');
console.log(work.items); // ['Buy milk'] - unexpected
// Better:
function SafeTodoList() {
this.items = [];
}
Arrays, strings, dates, functions, and regular expressions all inherit methods from their built-in prototypes. For example, arrays get methods from Array.prototype.
const numbers = [1, 2, 3];
console.log(numbers.map(n => n * 2)); // [2, 4, 6]
console.log(Object.getPrototypeOf(numbers) === Array.prototype); // true
console.log(Object.getPrototypeOf(Array.prototype) === Object.prototype); // true
JavaScript allows you to add methods to built-in prototypes, but this is risky in production code. It can conflict with future JavaScript features, third-party libraries, or other team code.
// Possible, but usually not recommended.
Array.prototype.sum = function() {
return this.reduce((total, number) => total + number, 0);
};
console.log([1, 2, 3].sum()); // 6
// Safer alternative:
function sum(numbers) {
return numbers.reduce((total, number) => total + number, 0);
}
Prototype pollution is a security problem where unsafe code lets user-controlled input modify shared prototypes such as Object.prototype. This can affect many objects in the application. Be careful when merging untrusted objects, especially if keys like __proto__, constructor, or prototype are allowed.
In real applications, use well-maintained libraries and keep dependencies updated. Avoid writing deep merge logic for untrusted data unless you fully understand the security risks.
function safeAssign(target, source) {
for (const key of Object.keys(source)) {
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
continue;
}
target[key] = source[key];
}
return target;
}
const settings = safeAssign({}, JSON.parse('{"theme":"dark"}'));
console.log(settings.theme); // dark
Prototype methods usually need dynamic this, so regular functions are normally the right choice. Arrow functions do not have their own this, which can cause confusing bugs when used as prototype methods.
function User(name) {
this.name = name;
}
// Good: regular function gets this from the call site.
User.prototype.greet = function() {
return `Hello, ${this.name}`;
};
const user = new User('Dev');
console.log(user.greet()); // Hello, Dev
The example below creates reusable course objects. Instance properties store each course's data, while prototype methods define shared behavior.
function Course(title, lessons) {
this.title = title;
this.lessons = lessons;
this.completed = 0;
}
Course.prototype.completeLesson = function() {
if (this.completed < this.lessons) {
this.completed += 1;
}
};
Course.prototype.getProgress = function() {
return `${this.completed}/${this.lessons} lessons completed`;
};
const js = new Course('JavaScript Prototypes', 12);
js.completeLesson();
js.completeLesson();
console.log(js.getProgress()); // 2/12 lessons completed
If someone asks "What is a prototype in JavaScript?", answer with the object lookup idea first. Then mention constructor functions and classes.
A strong answer: "A prototype is an object that another object can inherit from. When JavaScript cannot find a property directly on an object, it searches that object's prototype chain. Constructor functions and classes use prototypes to share methods across instances."
function Person(name) {
this.name = name;
}
Person.prototype.sayHi = function() {
return `Hi, I am ${this.name}`;
};
const person = new Person('Asha');
console.log(person.sayHi()); // Hi, I am Asha
console.log(Object.getPrototypeOf(person) === Person.prototype); // true
| Term | Meaning |
|---|---|
| [[Prototype]] | The internal link from one object to another object it inherits from. |
| Function.prototype | The object assigned as the prototype of instances created with new. |
| Object.getPrototypeOf(obj) | Returns the prototype of an object. |
| Object.create(proto) | Creates a new object with proto as its prototype. |
| instanceof | Checks whether a constructor's prototype appears in an object's prototype chain. |
| Object.hasOwn(obj, key) | Checks whether a property belongs directly to the object. |
Prototypes are the foundation of JavaScript inheritance. Every normal object can inherit from another object through its prototype. Constructor functions and classes use prototypes to share methods efficiently across instances. Once you understand property lookup, prototype chains, Object.create(), and how classes map to prototypes, JavaScript's object model becomes much easier to reason about.
class JavaScriptPrototypesPrototypeChainReview {
public static void main(String[] args) {
String state = "ready";
System.out.println("JavaScript Prototypes Prototype Chain: " + state);
}
}
String value = null;
if (value == null) {
System.out.println("JavaScript Prototypes Prototype Chain: handle the missing value before continuing");
}
Calling a value before checking whether it actually holds a function reference.
Trace the variable assignment, the property lookup, and the actual call expression.
Memorizing JavaScript Prototypes Prototype Chain without the situation where it is useful.
Connect JavaScript Prototypes Prototype Chain to a concrete JavaScript task.
Testing JavaScript Prototypes Prototype Chain only with the perfect input.
Include empty, missing, duplicate, incompatible, or failed cases when relevant.
Memorizing JavaScript Prototypes Prototype Chain without the situation where it is useful.
Connect JavaScript Prototypes Prototype Chain to a concrete JavaScript task.
A prototype is an object that another object inherits from. If a property is not found directly on an object, JavaScript searches the prototype chain.
Classes are modern syntax for creating constructor-style objects, but they still use prototypes internally. Instance methods declared in a class are placed on the class prototype.
<code>prototype</code> is a property on functions used when creating instances with <code>new</code>. <code>__proto__</code> is an older accessor for an object's internal prototype. Prefer <code>Object.getPrototypeOf()</code> instead of <code>__proto__</code>.
Usually no. Modifying built-in prototypes like <code>Array.prototype</code> can cause conflicts with libraries, other code, or future JavaScript features.
Explore 500+ free tutorials across 20+ languages and frameworks.