JavaScript: End of the Chain
Aug 6, 2013
Aug 6, 2013
Since coming to Hacker School I’ve learned JavaScript. One of the
first things you’re told about the language is that it uses prototypal
inheritance, which is actually a lot simpler than classical
inheritance and is pretty easily understood through a few
examples. This made sense to me, but I was never quite clear on
exactly how the prototype chain bottomed out. I rooted around the
Chrome REPL and the blogosphere for a while trying to find a good
answer and came up short. Eventually I ended up digging into
the spec
(a surprisingly readable document) in order to figure it out. What I
learned was either maddening or enlightening or perhaps both. Before
jumping into it, let’s review basic prototypal inheritance. Imagine we
have a constructor function for a Person, which has on its protoype
a sayName method:
var Person = function(name,age) {
this.name = name;
this.age = age;
};
Person.prototype.sayName = function () {
console.log("Hi, I'm " + this.name + "!");
};
Any new objects created with Person as their constructor will have
access to the sayName method via the prototype chain. To see this,
let’s create a sample person.
> var james = new Person("James",21);
> james.sayName();
"Hi, I'm James!"
OK, what actually happened there? When we say var james = new Person("James",21), we create a new object, james. The Person
function is then run with james as its context (so this refers to
james), and Person.prototype is assigned to
james.__proto__. This last bit is what’s critical for understanding
the prototype chain and how property lookup works. Every object has a
__proto__1, which can be thought of as a pointer to the prototype
of the object’s constructor. When the JavaScript runtime goes to do a
property lookup, it first checks if the object itself has a property
with the requested name. If the property is not found, whatever is
pointed to by the object’s __proto__ is checked for the property. If
it’s still not found there, the process repeats
(i.e. object.__proto__.__proto__ is checked), and again, and again, until
the prototype chain bottoms out. In our example above, the process can be
visualized as something like the following:

First, james itself is checked for a property sayName. No such
property is found, so james.__proto__ (i.e. Person.prototype) is
checked. At this point, sayName is found and the lookup is
done. But what about when the property isn’t found on
Person.prototype? What happens when a lookup fails? Something like:
> james.nope
undefined
It’s clear that Person.prototype.__proto__ will be checked, but what
does Person.prototype.__proto__ point to? These questions bothered me
even after I understood the gist of prototypal inheritance. I fooled
around in the Chrome REPL for a while trying to figure it out,
playing with Function, Object, etc. Eventually I discovered
the following:
> Function instanceof Object
true
> Object instanceof Function
true
> Function instanceof Function
true
> Object instanceof Function
true
Wat. This made just about zero sense. I was quite confused and so I spent a morning digging through the spec and figuring out what was what. Let’s walk through what I learned with the goal of understanding two things:
james.nope and get back undefined?Object and Function instances of themselves and each other?First we need to talk about what
Function and Object actually are. The spec says:
15.2.2 The Object Constructor
When
Objectis called as part of anewexpression, it is a constructor that may create an object.
As well as:
The production ObjectLiteral :
{ }is evaluated as follows:
- Return a new object created as if by the expression
new Object()whereObjectis the standard builtin constructor with that name.
Aha, so Object is the object constructor. It is a function that is
implicitly invoked when a new object literal is created. The spec says
something similar about Function. It is the function constructor,
and is implcitly invoked when a new function is created. What else
can we learn about these things?
15.2.3.1 Object.prototype
The initial value of
Object.prototypeis the standard built-in Object prototype object (15.2.4).
Additionally:
15.3.3.1 Function.prototype
The initial value of
Function.prototypeis the standard built-in Function prototype object (15.3.4).
OK, now we’re getting somewhere. Let’s make a chart to keep track of this stuff:

Function and Object are the constructors for functions and objects
respectively, and they each have a prototype, which is sort of a weird
hidden object that’s not accessible except through these
constructors. “standard built-in Function prototype object” and
“standard built-in Object prototype object” are a bit of a mouthful so
I’ll just refer to these as the “ur-function” and the “ur-object” from
here on out.
Now we’re going to read through the spec to fill in the blanks on this chart and then use it to answer the two questions we posed above.
First let’s look at the ur-object. Again quoting from the spec:
15.2.4 Properties of the Object Prototype Object
The value of the [[Prototype]] internal property of the Object prototype object is null . . .
Wait, what’s “the [[Prototype]] internal property”? It turns out
that this is just the “pointer” that the runtime uses to walk up the
prototype chain during property lookup; the thing that some
implementers have chosen to expose as __proto__. Knowing this, we
can fill in another part of our chart:

Aha! This is where the prototype chain bottoms out! Everytime the
runtime fails to find a property, its because it eventually got all
the way to looking at Object.prototype.__proto__, which is null.
We still need to figure out how the lookup gets here though. Let’s
keep filling in our chart. We know what Function.prototype and
Object.prototype are, but what about Function.__proto__ and
Object.__proto__? Any guesses? Here’s the spec:
15.2.3 Properties of the Object Constructor
The value of the [[Prototype]] internal property of the Object constructor is the standard built-in Function prototype object.
also,
15.3.3 Properties of the Function Constructor
. . . The value of the [[Prototype]] internal property of the Function constructor is the standard built-in Function prototype object (15.3.4).
Which makes our chart look like this:

This makes sense: Function and Object are both constructor
functions, so their prototypes are the ur-function. But notice that
there’s something weird going on here:
> Function.prototype === Function.__proto__
true
WTF?! Yes, this is true, go try it yourself. This also makes sense in a
perverse sort of way. Function is the constructor function for all
functions, so its the only thing that is its own constructor, which is
what Functon.prototype === Function.__proto__ means, afterall2.
We’re getting closer to understanding, but there’s a few more things
to fill in. We still don’t know what the ur-function’s __proto__ is;
let’s check the spec:
The value of the [[Prototype]] internal property of the Function prototype object is the standard built-in Object prototype object (15.2.4).
This leaves only the prototypes of the ur-function and ur-object
undefined. It turns out the spec has nothing to say about these, so they
are just that: undefined. This completes our chart:

Phew, that was exhausting. OK, now let’s use this chart to figure out
how the prototype chain bottoms out by revisiting our initial example
of a Person. What’s actually happening when we ask for
james.nope and get back undefined? First we check if james has a nope
property. Nope. Then we look at james.__proto__, which is
Person.prototype. Nope. Now we look as james.__proto__.__proto__,
which is Person.prototype.__proto__. Person.prototype is just an
object like any other. It was constructed by the object constructor,
so its prototype is Object.prototype, the ur-object. Let’s be sure
this is the case:
> james.__proto__.__proto__ === Object.prototype
true
Cool. Object.prototype doesn’t have a nope property, so we move on
to look at james.__proto__.__proto__.__proto__, which is the
ur-object’s __proto__, which is null. Here the chain bottoms out
and we return undefined.
If the above accurately describes what happens, we should be able to
prevent the bottom out by assigning to Object.prototype (the
ur-object).
> Object.prototype.yep = "Here I am!"
> james.yep
"Me too!"
Yes!
OK, so now we understand how property lookup bottoms out, but what about our other goal? Wherefore this madness?:
> Function instanceof Object
true
> Object instanceof Function
true
> Function instanceof Function
true
> Object instanceof Function
true
First let’s be sure we understand exactly what instanceof does.
According to MDN:
The
instanceofoperator tests whether an object has in its prototype chain theprototypeproperty of a constructor.
OK, got it. Now let’s look at each of the four cases above in turn.
First Function instanceof Object. I’ve highlighted Function’s prototype
chain in orange and Object’s prototype property in blue:

We see that the Function’s prototype chain terminates with
Object.prototype, which causes Function instanceof Object to be
true. This makes sense, since JavaScript functions are objects (they
can have properties assigned to them, etc.).
Now let’s look at a similar diagram for Object instanceof Function:

Object.__proto__ is the ur-function, Function.prototype, which means
Object instanceof Function is true. This makes sense too, since Object is
a function, namely the constructor function for objects.
Similar logic applies to Function instanceof Function:

This leaves us with Object instanceof Object:

Object is a constructor function, and all functions are objects, hence
Object instanceof Function is true.
So there you have it: a bunch of decisions that seem to make sense when considered individually lead to behaviors that are bizarre and confusing without careful examination. Hopefully this exploration helped you better understand how prototypes, property lookup, and object construction work, it certainly helped me.
Postscript: The content of this post was distilled from a presentation I gave at Hacker School which I jokingly titled WAT II: Revenge of JavaScript in homage to Gary Bernhardt’s WAT talk. If you find this sort of spelunking interesting, you should consider applying.
Addendum (April 10th, 2015): Note that the organization formerly known as Hacker School is now called the Recurse Center.
Note that __proto__ is not part of the spec. The spec refers
to an “internal [[Prototype]] property”, which some
implementers have chosen to expose via __proto__ because it
useful for learning and debugging. I use it here because the latest
versions of all the major web browsers and node have adopted this
convention, but be aware that __proto__ is not in any
way portable or to be relied upon in real code. ↩︎
i.e. x is y’s constructor if y.__proto__ === x.prototype, since
one of the things that happens during construction is that the new object’s
__proto__ is set to its constructors prototype. ↩︎