Prerequisites
Datatypes
Object
Try running the below code. We defined a new person object with properties firstname
and lastname
, and run toString
method on the object.
const person = {
firstname:"Rohan",
lastname:"Kamal"
}
console.log(person.toString()); // [object Object]
Did you notice the method toString
returned successfully without any errors, but we never defined toString
method in person
object. So where it came from?
To understand it, first, we need to understand a few methods,
Object.getOwnProperties(obj)
Object.hasOwn(obj, propertyName)
The first method Object.getOwnPropertyNames(obj)
returns all names of properties owned by the obj
. Let's try for our person
object.
const ownProperties = Object.getOwnPropertyNames(person);
console.log(ownProperties); // // [firstname, lastname]
The Second method Object.hasOwn(obj, propertyName)
checks, whether given a propertyName
property is owned by obj
or not. Let's try for our person
object for toString
property.
console.log(Object.hasOwn(person, 'toString')) //false
From the above, we can confirm that toString
does not belong to person
. So, the question is still the same, where toString
came from? Now let's see what else we have in person
object. Run the below code,
console.log(person)
/* {
firstname : "Rohan"
lastname : "Kamal"
[[Prototype]] : {
constructor : ƒ Object()
hasOwnProperty : ƒ hasOwnProperty()
isPrototypeOf : ƒ isPrototypeOf()
propertyIsEnumerable : ƒ propertyIsEnumerable()
toLocaleString : ƒ toLocaleString()
toString : ƒ toString()
valueOf : ƒ valueOf()
__defineGetter__ : ƒ __defineGetter__()
__defineSetter__ : ƒ __defineSetter__()
__lookupGetter__ : ƒ __lookupGetter__()
__lookupSetter__ : ƒ __lookupSetter__()
__proto__ : null
get __proto__ : ƒ __proto__()
set __proto__ : ƒ __proto__()
}*/
If you observed, toString
is present under [[Prototype]]
property of the person
object. It is an internal property in every object. We call it simply the prototype of an object. Now, the follow-up question arises of where this [[Prototype]]
came from. It means javascript is doing something behind the scene, every time we create an object.
What is a prototype?
The [[prototype]]
is an internal property of every object, initialized during object creation. It allows populating of common properties among objects created using the same constructor.
Let's understand it through person
object. When we created person
following steps were performed,
Call
new Object()
constructor.Creates a new Object with
fistname
andlastname
as properties.Assigns
[[prototype]]
of object asObject.prototype
.
Yes!, Whenever an object is created with object literal syntax, JavaScript calls Object()
constructor. It creates a new object and assigns [[prototype]]
as Object.prototype
. To verify it run the below code.
Object.getPrototypeOf(person) === Object.prototype; //true
Object.prototype
is nothing, just a property of the in-built object Object
, which gets assigned to [[prototype]]
property of every newly instantiated object created from Object()
constructor.
So, during the calling of toString
method over the person
object, JS firsts look for its own methods, if it failed to find any match then it goes into deeper into the object prototype [[prototype]]
. To learn more about Object.prototype
check this MDN Reference.
The most important point to note here is that the value of the [[prototype]]
depends on the constructor used to create the object. In the above example, we were playing with plain objects created using Object()
constructor so all objects were assigned Object.prototype
as prototype.
Suppose we create an array using array literal syntax as below,
const arr = [1, 3, 4, 5, 6];
Arrays are created using Array()
constructor in JavaScript, so every array object will have a prototype as Array.prototype
. Let's verify it
Object.getPrototypeOf(arr) === Array.prototype; // true