Understanding JavaScript Prototypes: A Deep Dive into Class Functionality

Introduction: Everything in JavaScript is an Object
You might be surprised by this subtitle, but it’s true: in JavaScript, everything is an object—either directly an object or it inherits from Object. After learning some jargon like __proto__, prototype, we circle back to this core concept. So, let’s start with the basics: What are Prototypes?
What is a Prototype?
A prototype is the mechanism by which JavaScript objects inherit properties from one another. Every object has some built-in properties—these come from its prototype.
const arr = [1, 2, 3, 4, 5];
const user = {
name: "Manas"
}
In the code above, we created an array that inherits from the Array prototype. This means we can access methods like map, filter, sort, reverse, etc., even though they weren’t explicitly declared. Similarly, the user object also inherits from JavaScript’s default Object.
JavaScript also has a typeof operator, which is a unary operator (takes only one operand). It's used to determine the type of a variable.
console.log(typeof arr) // object
console.log(typeof user) // object
When we access user. (user dot) in editor, we’ll notice more properties than just name. These additional properties come from the Object prototype.

Prototype Chaining
Earlier, we explored prototypes. The process by which inheritance flows is called the prototype chain.
Take the array example again. The variable arr inherits properties from the Array class, which itself inherits from the Object class. Eventually, this chain ends at null.
This hierarchical lookup is called the prototype chain—a term that sounds complex but is simple in practice.
You can try this with arrays or regular objects. Keep inspecting the prototype until you reach null—that’s the end of the chain.

__proto__ vs prototype vs Object.getPrototypeOf()
__proto__Used to access or set the internal
[[Prototype]]of an object.
Syntax:arr.__proto__prototypeUsed as a blueprint for creating objects (usually with constructor functions or classes).
Syntax:Array.prototypeObject.getPrototypeOf( )Used to retrieve the prototype of a specific object.
Syntax:Object.getPrototypeOf(arr)
All three methods help you access or understand the prototype chain—but they serve different purposes.

Why Is Everything an Object in JS?
Now that you understand __proto__, you can better appreciate that everything in JavaScript, even primitives like strings and numbers, inherit from Object—either directly or through their respective wrappers.


Shadowing Properties (Overriding Inherited Properties)
const date = new Date();
console.log(date.getFullYear()) // 2025;
date.getFullYear = () => "Hijacked";
console.log(date.getFullYear()) // Hijacked
In the code above, we override the built-in getFullYear() method of the Date object. Initially, it returns the current year (2025), but after shadowing, it returns "Hijacked".
How does this work?
First, JavaScript checks if the property exists on the object itself.
If not, it looks up the prototype chain.
If still not found, it returns
undefined.
const obj = {
name: "Manas",
age: 21,
greetings () {
console.log("Good morning");
}
}

When you type obj. in your editor, you’ll see your own properties and some inherited from Object. You can override any inherited method, which is what shadowing means.
Pre-ES6 Prototypes and Inheritance
Initially, JavaScript didn’t have classes. The class keyword was introduced in ES6. Before that, developers used constructor functions and prototypes for object creation.
const userA = {
fname: "Manas",
lname: "Pradhan",
fullName () {
return `${this.fname} ${this.lname}`;
}
}
const userB = {
fname: "John",
lname: "Doe"
}
console.log(userA.fullName()) // "Manas Pradhan"
console.log(userB.fullName()) // Uncaught TypeError: userB.fullName is not a function
In these two objects, we have to maintain the coding principle DRY (Don’t Repeat Yourself). Instead of writing again, we can add the below line.
userB.__proto__ = userA;
console.log(userA.fullName()) // "Manas Pradhan"
console.log(userB.fullName()) // John Doe

But this approach overrides the original prototype chain. Now userB inherits from userA directly and loses the default Object prototype.
ES6 Classes and Constructors

When we use the class keyword and create instances using new, the memory and prototype relationships look something like this:
userAanduserBare stored in the stack, holding references to the actual objects in the heap.The heap stores the object instances created using the
Userclass.These instances have their own properties (
fname,lname) and link back to shared methods (likegetFullName()).userA.__proto__points toUser.prototype.You can see this includes the constructor: class User and the method getFullName().
User.prototype.__proto__points to Object.prototype, which includes built-in methods liketoString,hasOwnProperty, etc.
Finally, Object.prototype.__proto__ is null—this ends the chain.
userA → User.prototype → Object.prototype → null
Conclusion
Understanding prototypes gives you deep insight into how JavaScript works under the hood. Whether you're debugging tricky inheritance bugs or explaining concepts in an interview, mastering prototypes is a powerful skill.
Now, open your browser console and explore the prototype chain yourself — it’s the best way to make it stick! 💻✨
Thanks for reading till the end!
I hope this helped you truly understand how prototypes work in JavaScript.
If you found this useful, feel free to share it or drop your thoughts in the comments — happy coding! 🚀

