In the last video, we saw how the prototype property on function constructors enabled us to immediately pass functions to all objects that were created by it.

Prototypal inheritance

So what has been happening here? How can we just add stuff to the constructor function’s prototype that made an object and have it immediately added to all of them?

First of all, this process we're talking about here is called prototypal inheritance. Each of the created objects inherits from its constructors prototype.

And understanding why it works is to understand the internal mechanics of JavaScript objects:

Every object has this prototype property. And it is used by the language itself to give the object data type itself certain properties and methods.

As you'll soon see however, it's not like properties that we've been looking at in the past that are available on objects. You can't just say object.prototype in order to get access to it.

So to see the differences let’s take a regular object and look at it’s prototype, which we can do with the method Object.getPrototypeOf:

Object.getPrototypeOf({});

If we look at the result, we see a ton of stuff. And all of these attributes are provided by the prototype of a special value called capital O Object. Which we can use to create new objects dynamically exactly like the constructor function we created. If you look at the constructor property of the new object, we see it is the capital O Object:

// constructor: ƒ Object()

So let's think about this, if we're being told that a basic object has a constructor function, capital O Object, based off of what we know about constructor functions through the last lecture, what will happen if we use this Object function. What will we get return to us? Think about this for a second:

If we use Object as a constructor function, we get a regular JavaScript object returned to us. In the familiar double curly brace syntax; the object literal syntax, as it is called:

new Object(); // {}

So based off of what we see here, if we take a look at the prototype of the student we created, student. Just stop right now and guess what you think you’ll see as student1's constructor function:

Object.getPrototypeOf(student1); // {addSubject: ƒ, constructor: ƒ}

We get our constructor function: Student. See that on the prototype we also have our addSubject function. As we add any new functions to the prototype in the future, you’ll see them included here.

And thinking about the nature of objects as reference types, can you see why this happens, why any changes made by our constructor function to its prototype will show up here?

Because whether an object is made by the original Object constructor or our own constructor, it will point to that constructor through this prototypal inheritance we’ve been talking about. Since objects are reference types, it refers to that prototype and can access any of its methods.

Prototype chain

In fact we speak of object prototypes as forming a chain. An object may have a custom constructor function that made it, but ultimately prototypes form a chain leading back to the prototype of the original Object, which gives all of the objects methods.

We can see this visually if we use an alternate way of accessing the object’s prototype, called the double underscore prototype, shortened to the dunder proto.

Let’s take our first todo and we get it’s prototype that its immediately pointing to. We see that it is the Student function constructor.

student1.__proto__;

We can confirm that it is infact pointing to Student's prototype by the following comparison:

student1.__proto__ === Student.prototype; // true

It is almost like we are creating our own custom data type. And note that the other major reference types have their own prototypes: Function.prototype and Array.prototype which give functions and arrays, respectively, their appropriate methods.

But then to see that prototypes form a chain, let’s add another dunder proto after the Student prototype:

student1.__proto__.__proto__ === Object.prototype; // true

We see that it is equal to the Object prototype, which is because Functions ultimately are a type of object.

Then, as we mentioned, Object.prototype forms the end of the chain. So what do you think will happen if we try to get the prototype of Object.prototype?

student1.__proto__.__proto__.__proto__; // null

Nothing. That’s the end of the line.

Never modify Object prototype

And one last note before we end this video. Make sure to not modify the original Object’s prototype. If you do so, you’re effectively changing the language itself and that can have untold consequences on the operation of your program.

Plus if you need to add any functionality to your objects, you can always make a constructor function like we focused on extensively in this video.

So after this, we’re going to see how function constructors perform the basis of a new construct within the Javascript language, classes