I am trying to understand behind the curtain scenes of Javascript and kind of stuck in understanding the creation of built in objects, specially Object and Function and the relation between them.
When I read that all the built in objects like Array, String etc are extension (inherited) from Object I assumed that Object is the first built in object that gets created and rest of the objects inherits from it. But it doesn't make sense when you come to know that Objects can only be created by functions but then functions are also nothing but objects of Function. It kind of started to sound like dilemma of hen and chicken.
The other extremely confusing thing is, if I console.log(Function.prototype)
it prints a function but when I print console.log(Object.prototype)
it prints an object. Why is Function.prototype
a function when it was meant to be an object?
Also, according to Mozilla documentation every javascript function
is extension of Function
object but when you console.log(Function.prototype.constructor)
it is again a function. Now how can you use something to create it self (Mind = blown).
Last thing, Function.prototype
is a function but I can access the constructor
function using Function.prototype.constructor
does that mean Function.prototype
is a function which returns the prototype
object
Best Answer
It is complicated, it is easy to misunderstand, and a great many beginner Javascript books get it wrong, so do not trust everything you read.
I was one of the implementers of Microsoft's JS engine in the 1990s and on the standardization committee, and I made a number of mistakes putting together this answer. (Though since I have not worked on this for over 15 years I can perhaps be forgiven.) It is tricky stuff. But once you understand prototype inheritance, it all makes sense.
Start by throwing away everything you know about class-based inheritance. JS uses prototype based inheritance.
Next, make sure you have a very clear definition in your head of what "inheritance" means. People used to OO languages like C# or Java or C++ think that inheritance means subtyping, but inheritance does not mean subtyping. Inheritance means that the members of one thing are also members of another thing. It does not necessarily mean that there is a subtyping relationship between those things! So many misunderstandings in type theory are the result of people not realizing that there is a difference.
This is simply false. Some objects are not created by calling
new F
for some functionF
. Some objects are created by the JS runtime out of nothing at all. There are eggs that were not laid by any chicken. They were just created by the runtime when it started up.Let's say what the rules are and maybe that will help.
null
.prototype
member of an object is typically not the prototype of the object.prototype
member of a function object F is the object that will become the prototype of the object created bynew F()
.__proto__
member that really does give their prototype. (This is now deprecated. Don't rely on it.)prototype
when they are created.Function.prototype
.Let's sum up.
Object
isFunction.prototype
Object.prototype
is the object prototype object.Object.prototype
isnull
Function
isFunction.prototype
-- this is one of the rare situations whereFunction.prototype
is actually the prototype ofFunction
!Function.prototype
is the function prototype object.Function.prototype
isObject.prototype
Let's suppose we make a function Foo.
Foo
isFunction.prototype
.Foo.prototype
is the Foo prototype object.Foo.prototype
isObject.prototype
.Let's suppose we say
new Foo()
Foo.prototype
Make sure that makes sense. Let's draw it. Ovals are object instances. Edges are either
__proto__
meaning "the prototype of", orprototype
meaning "theprototype
property of".All the runtime has to do is create all those objects and assign their various properties accordingly. I'm sure you can see how that would be done.
Now let's look at an example that tests your knowledge.
What does this print?
Well, what does
instanceof
mean?honda instanceof Car
means "isCar.prototype
equal to any object onhonda
's prototype chain?"Yes it is.
honda
's prototype isCar.prototype
, so we're done. This prints true.What about the second one?
honda.constructor
does not exist so we consult the prototype, which isCar.prototype
. When theCar.prototype
object was created it was automatically given a propertyconstructor
equal toCar
, so this is true.Now what about this?
What does this program print?
Again,
lizard instanceof Reptile
means "isReptile.prototype
equal to any object onlizard
's prototype chain?"Yes it is.
lizard
's prototype isReptile.prototype
, so we're done. This prints true.Now, what about
You might think that this also prints true, since
lizard
was constructed withnew Reptile
but you would be wrong. Reason it out.lizard
have aconstructor
property? No. Therefore we look at the prototype.lizard
isReptile.prototype
, which isAnimal
.Animal
have aconstructor
property? No. So we look at it's prototype.Animal
isObject.prototype
, andObject.prototype.constructor
is created by the runtime and equal toObject
.We should have said
Reptile.prototype.constructor = Reptile;
at some point in there, but we did not remember to!Make sure that all makes sense to you. Draw some boxes and arrows if it's still confusing.
The function prototype is defined as a function which, when called, returns
undefined
. We already know thatFunction.prototype
is theFunction
prototype, oddly enough. So thereforeFunction.prototype()
is legal, and when you do it, you getundefined
back. So it's a function.The
Object
prototype does not have this property; it is not callable. It's just an object.Function.prototype.constructor
is justFunction
, obviously. AndFunction
is a function.You are over-thinking this. All that is required is that the runtime creates a bunch of objects when it starts up. Objects are just lookup tables that associate strings with objects. When the runtime starts up, all it has to do is create a few dozen blank objects, and then start assigning the
prototype
,__proto__
,constructor
, and so on properties of each object until they make the graph that they need to make.It will be helpful if you take that diagram I gave you above and add
constructor
edges to it. You'll quickly see that this is a very simple object graph and that the runtime will have no problem creating it.A good exercise would be to do it yourself. Here, I'll start you off. We'll use
my__proto__
to mean "the prototype object of" andmyprototype
to mean "the prototype property of".And so on. Can you fill in the rest of the program to construct a set of objects that has the same topology as the "real" Javascript built-in objects? If you do so, you'll find it is extremely easy.
Objects in JavaScript are just lookup tables that associate strings with other objects. That's it! There's no magic here. You're getting yourself tied in knots because you are imagining constraints that do not actually exist, like that every object had to be created by a constructor.
Functions are just objects that have an additional capability: to be called. So go through your little simulation program and add an
.mycallable
property to every object that indicates whether it is callable or not. It's as simple as that.