by Hayden Betts
What we really mean when we talk about prototypes
- The non-enumerable
Not meaningful in itself until deliberately set to have some inheritance-related function. Most useful when used with constructor functions and factory functions (explanation coming!). Though all JS functions have the property by default. Contains a
constructorproperty, which refers to the original function.
For a long time, I was comfortable with definition 1, but not with definition 2.
Why does this distinction matter?
Before I understood the difference between “an object’s prototype,” and the “non-enumerable
prototypeproperty on functions,” I found myself confused by expressions like the following:
Array.prototype.slice.call([1, 2], 0, 1);// [ 1 ]
(sidebar: the first — but not the only — step to understanding the above is understanding
call(). Here’s a quick refresher just in case!)
A question I was not previously able to answer:
- “Why are we looking for
Arrayconstructor’s prototype? Shouldn’t the
Arrayconstructor itself contain the
slicemethod, and its prototype just contain some really low-level methods that all objects share?”
These questions were totally cleared up as I came to understand the design pattern that the
prototype property on
Array constructor functions exists to enable.
3 steps to understanding the prototype property on JS Functions
In order to understand the
prototype property on JS functions, you need to understand the design pattern it enables. I will build up an understanding of this pattern by first working through two less preferable alternatives.
Implementation 1: The Functional Class Pattern
Imagine we want to create a game in which we interact with dogs. We want to quickly create many dogs that have access to common methods like pet and giveTreat.
We could start to implement our game using the Functional Class Pattern as follows:
Let’s clean this up a bit by storing those methods in their own object. Then extend them inside of the
createDog factory function.
Though this implementation is easy to reason about, and conveniently reflects class-based-inheritance in other languages, it has at least one major issue: we are copying our method definitions to every dog object we create using our factory function
This takes up more memory than necessary and is not DRY. Wouldn’t it be nice if instead of copying method definitions to
casey, we could define our methods in one place. Then have
casey point to that place?
Refactor 1: Implementing a “Prototypal Class” Design Pattern
Prototypal inheritance gives us exactly what we asked for above. It will allow us to define our methods in one prototype object. Then have
casey, and infinitely more objects like them point to that prototype.
casey will then have access to all of the methods and properties of that prototype by reference.
NOTE: For the less familiar, there are many excellent tutorials out there that explain the concept of prototypal inheritance in much more depth than I do here!
A NOTE ON MY EXAMPLES BELOW: For pedagogical clarity, I use factory functions named
createDog, rather than ES5 constructor functions, to implement a prototypal model of inheritance. I choose to use factory functions because they have less ‘magic going on under the hood’ and ‘syntactic sugar’ than ES5 constructors. Hopefully, this makes it easier to stay focused on the issue at hand!
Great! Now the objects corresponding to
casey do not themselves contain copies of the methods
pet. Instead, the objects look up those methods in their prototype
But wouldn’t it be nice if
methodsForShowingAffection were encapsulated in the
createDog factory function? Doing so would make it clear that these methods are intended for use only with that function. So a simple refactor leaves us with:
Refactor 2: Prototypal Inheritance + the prototype property on factory functions
Great! But isn’t
prototype property on every function, including one on our factory function
Note that there is nothing special about this
prototype property. As shown above, we could achieve exactly the same result by setting the prototype of
createDog to a separate object called
methodsForShowingAffection. The normalcy of the
The MDN article on prototypes.