JavaScript is an object oriented programming language. However unlike other object oriented languages like C++ and Python it doesn't have classes. Instead JavaScript has prototypal inheritance.
In prototypal object oriented programming languages you only have objects. Inheritance is achieved via one of two ways:
- Delegation
- Concatenation
Suppose I have an object called rectangle
as follows:
var rectangle = {
height: 5,
width: 10,
area: function () {
return this.width * this.height;
}
};
Now I can calculate the area of this rectangle by calling rectangle.area
. However what if I wanted to create another rectangle with a different width
and height
? This is where your object
function is used (this function is available natively in most JavaScript interpreters as Object.create
):
var rectangle2 = Object.create(rectangle);
rectangle2.height = 10;
rectangle2.width = 20;
alert(rectangle2.area()); // 200
What's happening here is that the object rectangle2
is inheriting from the object rectangle
via delegation. To help you visualize what's happening look at the following diagram:
null
^
| [[Proto]]
|
+-------------------------------+
| Object.prototype |
+-------------------------------+
| ... |
+-------------------------------+
^
| [[Proto]]
|
+-------------------------------+
| rectangle |
+-------------------------------+
| height: 5 |
+-------------------------------+
| width: 10 |
+-------------------------------+
| area: ... |
+-------------------------------+
^
| [[Proto]]
|
+------------------------------+
| rectangle2 |
+------------------------------+
| height: 10 |
+------------------------------+
| width: 20 |
+------------------------------+
The Object.create
function creates an object (rectangle2
) whose internal [[Proto]]
property points to the object rectangle
(the prototype of rectangle2
).
When you try to access a property on rectangle2
JavaScript first tries to find the property on rectangle2
itself. If it can't find the property on rectangle2
then it tries to find it on the prototype of rectangle2
(i.e. rectangle
) and so on until:
- It find the property, in which case it returns the value associated with that property.
- It exhausts the prototype chain (i.e. it reaches
null
), in which case it returns undefined
.
Hence if I try to access rectangle2.width
it will return 20
. However if I try to access rectangle2.area
it will return the rectangle.area
function instead of undefined
. That's prototypal inheritance for you in a nutshell.
Now in you code you first create an object u1
:
var u1 = {
name: "adam"
};
Then you create an object u2
which inherits from u1
:
var u2 = Object.create(u1);
After that you set a new name
property on u2
(this doesn't overwrite the name
property of u1
, it simply shadows it):
u2.name = "roman";
Then you delete the name
property of u1
(this doesn't affect the name property of u2
):
delete u1.name;
So when you log u2.name
it displays roman
:
console.log(u2.name); // roman
Then you delete the name
property of u2
as well:
delete u2.name;
Hence when you log u2.name
again it displays undefined
:
console.log(u2.name); // undefined
Finally you set u1.name
to tytus
:
u1.name = "tytus";
Hence when you log u2.name
again it displays tytus
because u2
delegates to u1
:
console.log(u2.name); // tytus
I hope this helped you understand prototypal inheritance. If you want to learn more then read my blog post on Why Prototypal Inheritance Matters.