Have you ever thought that everything in JavaScript works like an object? Or how inheritance actually works behind the scenes? What is the difference between __proto__ And prototype?
If these questions have crossed your mind, you’re not alone. These are some of the most basic JavaScript concepts, yet they often confuse developers.
In this tutorial, we’ll cover prototypes, prototype chains, and inheritance in JavaScript. Finally, you’ll understand the “what,” “why,” and “how” of JavaScript’s prototype system.
Here is what I will cover:
Conditions
To get the most out of this tutorial, you should:
Basic understanding of JavaScript fundamentals
Familiarity with objects, functions and classes in JavaScript
Knowledge of how to declare and use variables
Experience working with
newKeyword (helpful but not required)
The String Method Mystery
Let’s start with a simple example that shows something interesting about JavaScript:
let name = "Shejan Mahamud";
After declaring this variable, we can use string methods like:
name.toLowerCase();
name.toUpperCase();
It seems normal at first glance, but wait – something unusual is happening. Notice something strange here? We are using dot notation on string primitives.
Here’s the surprising part: We know that strings are primitive types in JavaScript, not objects. So how can we use dot notation to access methods? However, dot notation generally only works with objects.
The answer to this mystery lies in understanding how JavaScript handles primitives and prototypes. But before we get there, let’s first look at how objects work internally.
How objects work internally
When you create an object in JavaScript like this:
const info1 = {
fName: "Shejan",
lName: "Mahamud"
};
JavaScript does some interesting work behind the scenes. It automatically adds a hidden property called __proto__ This property points to your object Object.prototypewhich is the prototype of the built-in Object class.
You might be surprised: it does Object.prototype There is also a __proto__? Yes, it does, but it’s worth it null. This is the reason Object.prototype The prototype is at the top of the chain and does not inherit from anything else.
Let’s look at a more complicated example to understand this better:
const info1 = {
fName1: "Shejan",
lName1: "Mahamud"
};
const info2 = {
fName2: "Boltu",
lName2: "Mia",
__proto__: info1
};
const info3 = {
fName3: "Habu",
lName3: "Mia",
__proto__: info2
};
In this example, we have intentionally set __proto__ property for info2 And info3. Now here’s an interesting question: Can we get access? fName1 from info3?
console.log(info3.fName1);
Yes, we can! Let’s understand how it works.
Understanding the prototype chain
When you try to access a property on an object, JavaScript follows a specific lookup process:
First, it looks for the property in the object itself (the base object).
If it’s not found there, it looks in the object
__proto__If it still doesn’t find it, it continues, checking each one
__proto__Until he either finds or reaches the propertynull
With our example info3.fName1:
JavaScript sees first
info3– And it doesn’t get itfName1Then it checks
info3.__proto__which refers toinfo2– It is not foundfName1There, eitherNext it checks
info2.__proto__which refers toinfo1– And it gets itfName1Here!
It is called Prototype chainand that’s how inheritance works in JavaScript. Here is a visual representation:
┌────────────┐
│ info3 │
│ fName3 │
│ lName3 │
└────┬───────┘
│ __proto__
▼
┌────────────┐
│ info2 │
│ fName2 │
│ lName2 │
└────┬───────┘
│ __proto__
▼
┌────────────┐
│ info1 │
│ fName1 │
│ lName1 │
└────┬───────┘
│ __proto__
▼
┌─────────────────┐
│ Object.prototype│
└────┬────────────┘
▼
null
Each object points through it to the next object in the chain __proto__ property This chain continues until it is reached null.
Why is everything an object in JavaScript?
Now let’s solve the mystery we started with: How can primitive types use object methods?
In JavaScript, almost everything behaves like an object, although primitive types (such as string, number, and boolean) aren’t technically objects. It works through a process called Autoboxing or The wrapper object.
Let’s see this in action:
let yourName = "Boltu";
When you try to use a method on this string:
yourName.toLowerCase();
Here’s what JavaScript does behind the scenes:
This temporarily wraps the primitive value in a wrapper object:
new String("Boltu")This is a temporary object
__proto__automatically points to itString.prototypefound in the method
String.prototypeAnd executedAfter the operation completes, the wrapper object is discarded
yourNameReturns to be a simple primitive value
This is why you can use methods on primitives even though they are not objects. JavaScript creates a temporary object, uses it to access a method, then disposes of it.
The same process occurs with other archetypes:
And so this elegant system is why developers often say that “everything in JavaScript is an object” – even when it’s not technically true, it behaves that way when needed.
The difference between __proto__ And prototype
This is the most confusing aspect of JavaScript for many developers. Let’s break it down clearly.
what is prototype?
When you create a function or class in JavaScript, the language automatically creates a blueprint object called prototype. It happens behind the scenes.
Here is an example:
function Person(name) {
this.name = name;
}
When JavaScript sees this function, it does this internally:
Person.prototype = {
constructor: Person
};
Person The function now has a hidden property called prototypewhich is an object that contains constructor Property
You can add methods to this prototype object:
Person.prototype.sayHi = function() {
console.log("Hi, I'm " + this.name);
};
what is __proto__?
__proto__ is a property that exists on everything (arrays, functions, objects – everything). It is an internal reference or pointer that indicates which prototype the object inherits from.
By default, when you create an object, its __proto__ On to the points Object.prototype.
How do they work together?
When you use new Keyword:
const p1 = new Person("Shejan");
JavaScript performs these steps internally:
Creates a new empty object:
p1 = {}Specifies the object
__proto__:p1.__proto__ = Person.prototypecalls the constructor function with the new object:
Person.call(p1, "Shejan")Returns the object:
return p1
Now when you try to access a method:
p1.sayHi();
Searches JavaScript sayHi i p1 First when it doesn’t find it, it checks p1.__proto__which refers to Person.prototypewhere the method is defined.
The relationship can be expressed as:
p1.__proto__ === Person.prototype;
Person.prototype.constructor === Person;
In summary:
How prototypes work with functions
Let’s see a complete example with functions:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.introduce = function() {
console.log(`Hi, I'm ${this.name} and I'm ${this.age} years old.`);
};
const person1 = new Person("Alice", 25);
const person2 = new Person("Bob", 30);
person1.introduce();
person2.introduce();
console.log(person1.__proto__ === Person.prototype);
console.log(person2.__proto__ === Person.prototype);
console.log(person1.__proto__ === person2.__proto__);
The key benefit here is memory efficiency: introduce The method exists only once Person.prototypebut all instances can access it through the prototype chain.
How Prototypes Work with Classes
Introduced by ES6 class The syntax, which looks different but works the same under the hood:
class User {
constructor(name) {
this.name = name;
}
sayHi() {
console.log(`Hi, I'm ${this.name}`);
}
}
const user1 = new User("Charlie");
user1.sayHi();
console.log(typeof User);
console.log(User.prototype);
console.log(user1.__proto__ === User.prototype);
Classes are basically prototypes based on JavaScript’s prototype inheritance. Internally:
A class is still a constructor function
The methods defined in the class are invoked
ClassName.prototypeMade for example
newIt’s theirs__proto__Set to the class prototype
This means that what we learned about function prototypes also applies to classes.
The result
Understanding prototypes and the prototype chain is fundamental to mastering JavaScript. These concepts form the basis of how JavaScript implements inheritance and object-oriented programming.
The key path
Let’s recap what we’ve learned:
It happens in everything
__proto__: This property points to the prototype from which the object inherits, enabling the prototype chain search mechanism.There are functions and classes
prototype: This property serves as a blueprint for instances created with RabnewKeywordThe prototype chain enables inheritance: When JavaScript cannot find a property on an object, it walks up the prototype chain until it finds or reaches the property.
null.Primitive wrappers use objects: Although primitives are not objects, JavaScript temporarily wraps them in objects to provide access to methods.
Class are synthetic sugars: Modern
classThe syntax is cleaner, but it still uses prototypes under the hood.
JavaScript may seem strange at first, but once you understand how it works under the hood, you’ll appreciate its elegant and flexible design.
Happy coding!