Context & About Me
I am a B.Tech IT student currently re-learning JavaScript internals deeply to master Backend Engineering.
I learned these concepts from Hitesh Choudhary (channel name: Chai aur Code). I watch his videos, understand them, and write notes on what he explains. This blog is a compilation of those notes, where I converted his Hindi explanations into my own English understanding to make these concepts simple.
1. Object Literals and the this Keyword
Object Literal: Creating an Object. The Object is the base unit of the JS language.
Object Example
const user = {
username: "Hamada",
loginCount: 24,
isLoggedIn: true,
greeting: function () {
// 'this' keyword represents context.
// It answers: "We are talking about which user object?"
// If there are other similar objects, then what?
console.log(`hello! ${this.username} `);
console.log(" this --> ", this); // this represents the current user object
},
};
// Accessing properties
console.log("username --> ", user.username);
// Accessing methods
// Reference
console.log("method reference --> ", user.greeting);
// Executing
console.log("method executing --> ", user.greeting());
2. Why do we need a Constructor?
Reason 1: If I need to make another user object having similar fields, then I need to copy-paste the code again.
let user2 = {
username: "king",
loginCount: 2,
isLoggedIn: false,
greeting: function () {
console.log(`hello! ${this.username} `);
console.log(" this --> ", this);
},
};
Reason 2: Why do we create new multiple instances from one Object / Class using the "new" keyword? Why can't we use a single instance?
Let's understand this with a function example.
function displayUsers(username, age, email) {
// myUsername = username; but we mostly keep the same names.
// username = username; if we want the same name for var in function as argument to store, this way causes some issues.
this.username = username; // so we use "this" to tell username in this function
this.age = age;
this.email = email;
return this;
// Also, if we are using the "new" keyword and creating instances for this function,
// we don't need to write "return this". The constructor automatically does this.
// But explicitly writing it is good practice.
}
EXPLANATION: The "return this" behavior
In a normal function, we write
return thisto get the object back.BUT, when we use the
newkeyword, JavaScript is smart! Thenewkeyword AUTOMATICALLY (implicitly) returnsthis(the new object) for us.So, even if you don't write
return this, it will still work perfectly withnew. Writing it explicitly is just like a "safety backup" or good practice, but not strictly needed.
SUPER IMP POINT FOR INTERVIEWS:
If your function returns a "Primitive" (like a string, number, or true/false), the
newkeyword IGNORES it and still returns your object.BUT, if your function returns a "Different Object" (like
{name: "luffy"}), thennewwill throw away your intended object and return that different object instead!
3. The new Keyword and Instances
Let's see why we need instances.
// userOne created
const userOne = displayUsers("Hamada", 12, "hamada@g.com");
const userTwo = displayUsers("King", 24, "king@kong.in");
console.log(" userOne --> ", userOne);
// --> Working correctly when we use that function once only meaning we create only userOne.
username: 'Hamada'
age: 12...
// userOne created
const userOne = displayUsers("Hamada", 12, "hamada@g.com");
// userTwo created
const userTwo = displayUsers("King", 24, "king@kong.in");
console.log(" userOne --> ", userOne);
/*
userOne is giving output -->
username: 'King'
age: 24...
*/
When we create userTwo with the same function instance, this time it won't work.
That's why we need to create different instances to avoid overwriting values.
const userThree = new displayUsers("Luffy", 18, "luffy@op.com");
const userFour = new displayUsers("Gojo", 28, "gojo@op.com");
console.log("userThree --> ", userThree);
// userThree --> displayUsers { username: 'Luffy', age: 18, email: 'luffy@op.com' }
// Worked perfectly
Few points about how the "new" keyword works
- First, it creates a new empty object.
- The
newkeyword calls a constructor function. - The constructor function packs all arguments and definitions and returns them to you.
- Then all these arguments are injected into the
thiskeyword. - You get all these arguments inside
this.
Constructor Property
console.log(userThree.constructor); // --> [Function: displayUsers]
// The constructor property is a reference to itself, meaning a reference to the displayUser function.
instanceof Operator
One operator to check if an instance is created from the original/wanted object or class.
console.log(
"is userThree is instance of displayUser func --> ",
userThree instanceof displayUsers,
); // --> true
4. What is a Prototype?
Prototype is the default behavior / core working mechanism of JavaScript. We also call it "prototypic behavior".
In JS, everything is an Object, or we can say everything is made from an Object.
Diagram: The Prototype Chain
Every element/component has its own prototype (default properties and methods).
Inside each element's prototype, there is the prototype of its parents as well. Then again, inside that parent's prototype, its parent exists (meaning the first element's grandparent prototype exists)... and it continues until we reach the Object's prototype. That is the end; after that, we get
null.Object does not have any parent.
One interesting nature of JS
If it does not find any method or property in that element's prototype, then it goes deeper into its parent's prototype and tries to find that property or method. If not found, it goes further into the depths of its grandparent's prototype.
prototype -----> prototype ----->(Object) prototype -----> Null
Due to this nature, and because everything is made from Object, other elements like Function and Array behave like Objects too.
Example: Function acting like an Object
// create one function
function additionTwo(num) {
return num + 2;
}
// I try to create a key-value pair like an Object into this function
additionTwo.username = "Luffy";
// working - normally
console.log(additionTwo(5)); // -> 7
// accessing its key-value pair
console.log(additionTwo.username); // -> Luffy
How is this possible?
This is possible due to the interesting JS nature explained above.
5. How .prototype looks
console.log(additionTwo.prototype); // -> { }
It looks like it is an empty object, but it is not empty. It is not made to be visible; it is for the internal core to use and access.
The "this" keyword and its working in Prototype
The
thiskeyword is also connected to the prototype.It helps to set/create context (context means: who is calling? who is creating? who is accessing? like which element is it? on which elements do we apply operations/methods?).
someElement.prototype --> { }
One IMP Line ~ very deep line:
"That
{ }prototype means there are some default set methods and some internal properties, so their/that method's and property'sthis(context) is in that prototype{ }."
"prototype{ }= other all set hidden properties +this(context) of that method."
Let's see one example on this and how it sets context.
function dishAndPrice(name, price) {
this.name = name;
this.price = price;
console.log(` Dish added into menu `);
}
Now let's create our own methods for the function.
Without "this"
dishAndPrice.prototype.tellMenu() = function() {
console.log(`Menu : Dish name is ${name} and price is ${price}`);
};
let Pizza = new dishAndPrice("Veg Jumbo Pizza", 250 );
Pizza.tellMenu();
// output -->
// Throw Error --> ReferenceError: name is not defined
As we know, both instances share the same single prototype. All these methods and properties are kept in the prototype, so when any instance calls the tellMenu method, it gets confused: "Which one is calling me?" and "Which name and price should I print?"
To avoid this kind of confusion, we use this.
With "this"
dishAndPrice.prototype.tellMenu = function () {
console.log(`Menu : Dish name is ${this.name} and price is ${this.price}`);
};
let pizza = new dishAndPrice("Veg Jumbo Pizza", 250);
let noodles = new dishAndPrice("Hakka Chilly Noodles", 80);
pizza.tellMenu();
noodles.tellMenu();
// output -->
// Menu : Dish name is Veg Jumbo Pizza...
Now,
tellMenuknows whose name and price to print when it is called.Here we tell it: "Print the name and price of whichever instance is calling you."
This is the context we are talking about, and the
thiskeyword helps to create it.
6. Theory behind the working of the "new" keyword
It is deep and hard to understand. Here is what happens behind the scenes when the new keyword is used:
A new object is created: The
newkeyword initiates the creation of a new JavaScript object.A prototype is linked: The newly created object gets linked to the prototype property of the constructor function. This means that it has access to properties and methods defined on the constructor's prototype.
The constructor is called: The constructor function is called with the specified arguments, and
thisis bound to the newly created object. If no explicit return value is specified from the constructor, JavaScript assumesthis(the newly created object) to be the intended return value.The new object is returned: After the constructor function has been called, if it doesn't return a non-primitive value (object, array, function, etc.), the newly created object is returned.
7. Prototypal Inheritance
Goal: Our goal is that our own custom-created method should be available for all elements of that kind.
E.g., if I create a hello() method for Array, then all Arrays should have this method automatically.
Example: String
let myName = "Luffy";
console.log(myName.length); // -> 11
// The length property is counting white spaces also.
// So we want a property that gives us the actual length (remove spaces and then count).
// Give it the name "trueLength".
And this method should be available in every String. Not only for the parent/original element but also its instances.
Flow of inheritance (From which direction are properties passed?)
IMP Diagram (Flow of Inheritance)
Only Down Flow (Parent ---> Child)
No Up Flow (Child ---> Parent)
Down Flow (Parent ---> Child)
I want one Method in all (Array, Function, Object, etc.). As we know everything is an Object, if we inject our custom method into Object, then it will be available in all due to the inheritance flow.
// Creating and injecting our custom Method
Object.prototype.greeting = function () {
console.log("Hello! Nice to meet you");
};
let myHeros = ["Superman", "Batman", "Iron Man"]; // array
let animal = { name: "parrot", ability: "fly" }; // object
// array --> it inherits
myHeros.greeting(); // --> Hello! Nice to meet you
// object --> it inherits
animal.greeting(); // --> Hello! Nice to meet you
--> Yes, properties and methods flow of inheritance is from Parent ----> Child.
Up Flow (Child ---> Parent)
Let's understand: does our flow of inheritance flow backward?
// creating custom method for Array
Array.prototype.goodNight = function () {
console.log("Good Night");
};
//* array --> it inherits
myHeros.goodNight(); //* --> Good Night
// object (parent) --> //! it does not inherit
// animal.goodNight(); //! --> animal.goodNight is not a function
--> No, properties does not flow Up (Child ā> Parent )
Answer for our earlier task: creating trueLength for String
String.prototype.trueLength = function () {
console.log(this.trim().length);
};
// using our custom method
myName.trueLength(); // --> 5
8. Modern Syntax vs Old Syntax for Inheritance
#1 __proto__ (Older Syntax)
__proto__ is consider as a property.
const livingThing = { isGrowing: true };
const plant = { name: "Apple Tree" };
const fruit = {
haveSeeds: true,
// Syntax 1 (inside)
__proto__: plant,
};
// Syntax 2 (outside)
plant.__proto__ = livingThing;
// Let's check: did our inheritance work?
console.log(fruit.isGrowing); // --> true
#2 Object.setPrototypeOf (Modern Syntax)
const vehical = { haveFourWheels: true };
const car = { name : "Mercedes Benz S-Class" };
// Modern Syntax
Object.setPrototypeOf( car, vehical );
Credits & Source:
- Learning Source: Hitesh Choudhary (Chai aur Code)
- MDN Doc
- My Code Repo: Prototype and new in JS


Top comments (3)
Careful... not every object has
Object.prototypein its prototype chain.Thanks for pointing this out!! Iām trying to learn JS deeply to have better in-depth knowledge, but I haven't come across this specific case or read about it yet.
I searched about it ... I found that you are talking about creating a pure object that doesn't inherit anything not even the object's common methods
Thanks for sharing this.
Yes... it's trivial, and sometimes useful, to create such objects:
Some built-in functions also return objects with
null-prototypes:Object.groupBybeing an example.