prototype property on all
1 2 3 4 5 6 7 8 9 10 11
By default, the
prototype property points to a plain object. You can add
properties to this object to give any new objects created from this function
some behaviour or data. Notice I intentionally did not specify a
person object, to show that it uses the
name property on the
Below is an alternative way of creating a new object, using Object’s
function (introduced in Ecmascript 5):
1 2 3 4 5 6 7 8 9 10 11 12 13
This is a little bit of syntactic sugar around the cumbersome way of creating constructor functions and molding the prototype object.
We will miss out on some type checking goodness if we adopt this way since
person is created from the
Object constructor (not the
constructor). Or quite simply, we can’t do this:
The important thing to realize is that the
person instance (shown above) now
has an internal reference to the prototype object. Since I did not define a
name property on
person, it will first see if it exists on the local
object, and since in this case it doesn’t, it will traverse the prototype chain
until it is found. Because it exists on the most immediate prototype object,
it will return anonymous. This is in a nutshell how property look ups work in
Here’s a diagram:
To illustrate further:
will not list
name. This function lists all properties that are local to the
simple object only. It does not traverse the chain of prototypes.
However, if we do this:
1 2 3 4 5
we are defining a property on the
person object called
name. You may think
that this is overriding
name in the prototype object, but it is actually
defining a new property on
person, the local object. The property lookup
will find it immediately on
person and will have no need to traverse the
prototype chain. If we delete this property:
1 2 3
name property no longer exists on the local object, and therefore is
looked up on the prototype object and found there. This illustrates a clear
distinction between the local and prototype objects, where the prototype is
like a fall back if a property is not found on the local.
However, if we did this:
1 2 3 4 5 6
the two objects that reference the
prototype object can no longer find
Prototypes in Ruby?
In Ruby, we can take advantage of some interesting features of the language to implement the prototype pattern, even though it’s not something you would commonly do.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Notice there is no class definition here to define behaviour. You may think that
the above code is circumventing Ruby’s class system, but what we’re really doing
is opening the object’s singleton class and adding behaviour to it.
Singleton classes in Ruby are an important concept that allow you to add ad hoc
behaviour to an object. This class is placed at the head of the ancestor
person is created from the
Object class, the singleton
class’s super class is
1 2 3 4 5 6
Notice that you call
class on person, it still returns
singleton class is unseen in this case which is why some folks refer to them as
The disadvantage of this approach is that we have no meaningful way to do type
adam object is always an
Object, but how do we check that
it’s a person?
The reason why the above returns false is because the singleton class is also
person refer to two different singleton classes with the
same behaviour. This demonstrates an important thing about singleton classes,
that all objects get their own singleton class.
Ruby Methods are really just message handlers
Ruby uses a paradigm of sending a message rather than the common paradigm of calling a method.
1 2 3
You can imagine the message (method call) is sent along a message bus (the
class hierarchy). If we consider the diagram above, the message bus is the
class hierarchy, starting from the singleton class object all the way to the
BasicObject class object. A message is captured and handled if one of the
classes in the hierarchy has a defined method of the same name as the message.
If no method is found in the hierarchy, than a
NoMethodError is raised. Notice
this method of sending a message along a bus in the hope that it will be
traversing the prototype chain. A key difference however, is that if it’s not
found, it is handled by a private method on
missing_method, which will actually raise the
NoMethodError we just talked
about. You can override this to do you’re own method missing handling.
as a linked list of objects. The process of resolving a property starts on the
local object and works all the way down the chain until you reach the
offset by its awesome functional component (which is out scope for this series
Ruby’s magic on the other hand, is with it’s class system, which was too much to cover in this blog post. Instead we demonstrated that we could setup a similar prototype system using Ruby, demonstrating singleton classes as a result. You obviously wouldn’t use this pattern as a day to day tool, but it’s interesting to find the parallels. We also introduced the idea that Ruby broadcasts messages along a class message bus. And that method definitions are simply message handlers that could be stationed anywhere along that bus.