JavaScript – Solving Function Mysteries in Object-Oriented Design

functionsjavascriptobjectobject-oriented-design

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

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.

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.

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.

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.

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.

This is simply false. Some objects are not created by calling new F for some function F. 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.

  • Every object instance has a prototype object.
  • In some cases that prototype can be null.
  • If you access a member on an object instance, and the object does not have that member, then the object defers to its prototype, or stops if the prototype is null.
  • The prototype member of an object is typically not the prototype of the object.
  • Rather, the prototype member of a function object F is the object that will become the prototype of the object created by new F().
  • In some implementations, instances get a __proto__ member that really does give their prototype. (This is now deprecated. Don't rely on it.)
  • Function objects get a brand-new default object assigned to prototype when they are created.
  • The prototype of a function object is, of course Function.prototype.

Let's sum up.

  • The prototype of Object is Function.prototype
  • Object.prototype is the object prototype object.
  • The prototype of Object.prototype is null
  • The prototype of Function is Function.prototype -- this is one of the rare situations where Function.prototype is actually the prototype of Function!
  • Function.prototype is the function prototype object.
  • The prototype of Function.prototype is Object.prototype

Let's suppose we make a function Foo.

  • The prototype of Foo is Function.prototype.
  • Foo.prototype is the Foo prototype object.
  • The prototype of Foo.prototype is Object.prototype.

Let's suppose we say new Foo()

  • The prototype of the new object is Foo.prototype

Make sure that makes sense. Let's draw it. Ovals are object instances. Edges are either __proto__ meaning "the prototype of", or prototype meaning "the prototype property of".

enter image description here

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.

function Car(){ }
var honda = new Car();
print(honda instanceof Car);
print(honda.constructor == Car);

What does this print?

Well, what does instanceof mean? honda instanceof Car means "is Car.prototype equal to any object on honda's prototype chain?"

Yes it is. honda's prototype is Car.prototype, so we're done. This prints true.

What about the second one?

honda.constructor does not exist so we consult the prototype, which is Car.prototype. When the Car.prototype object was created it was automatically given a property constructor equal to Car, so this is true.

Now what about this?

var Animal = new Object();
function Reptile(){ }
Reptile.prototype = Animal;
var lizard = new Reptile();
print(lizard instanceof Reptile);
print(lizard.constructor == Reptile);

What does this program print?

Again, lizard instanceof Reptile means "is Reptile.prototype equal to any object on lizard's prototype chain?"

Yes it is. lizard's prototype is Reptile.prototype, so we're done. This prints true.

Now, what about

print(lizard.constructor == Reptile);

You might think that this also prints true, since lizard was constructed with new Reptile but you would be wrong. Reason it out.

  • Does lizard have a constructor property? No. Therefore we look at the prototype.
  • The prototype of lizard is Reptile.prototype, which is Animal.
  • Does Animal have a constructor property? No. So we look at it's prototype.
  • The prototype of Animal is Object.prototype, and Object.prototype.constructor is created by the runtime and equal to Object.
  • So this prints false.

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 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?

The function prototype is defined as a function which, when called, returns undefined. We already know that Function.prototype is the Function prototype, oddly enough. So therefore Function.prototype() is legal, and when you do it, you get undefined back. So it's a function.

The Object prototype does not have this property; it is not callable. It's just an object.

when you console.log(Function.prototype.constructor) it is again a function.

Function.prototype.constructor is just Function, obviously. And Function is a function.

Now how can you use something to create it self (Mind = blown).

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" and myprototype to mean "the prototype property of".

var myobjectprototype = new Object();
var myfunctionprototype = new Object();
myfunctionprototype.my__proto__ = myobjectprototype;
var myobject = new Object();
myobject.myprototype = myobjectprototype;

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.

Related Topic