Skip to content

Latest commit

 

History

History
69 lines (37 loc) · 4.28 KB

prototypical-inheritance.markdown

File metadata and controls

69 lines (37 loc) · 4.28 KB

Title: Prototypal Inheritance Author: Tim Caswell Date: Tue Feb 09 2010 13:44:09 GMT-0600 (CST) Node: v0.1.102

In almost all modern programming languages we use the concept of Object Oriented Programming (OOP) to help manage the complexity of today's software. The biggest challenge in modern software is in fact managing the complexity of it.

Most languages do this with a variant OOP called Classical OOP. This is the one you see in Java, C#, C++, PHP, Ruby, and Python. It has the idea that classes should be separate from instances. Classes hold behavior and instances hold data.

While this is a great abstraction, I would like to experiment with other ideas. Prototypal inheritance gets rid of the distinction between class and instance, between constructor and method. It's just objects with inherited and local properties.

So what does JavaScript have?

From what I hear (I wasn't there at the time), JavaScript was initially a prototypal inheritance system. It was super simple like the rest of the language. But then Netscape decided to make it be more like Java and added the idea of constructors to the language. Hence pseudo classes were born.

Classical OOP

<prototypal-inheritance/classical.js*>

Here we have a class like object Person. Actually it's just a regular JavaScript function, but that's how it works, there are no real classes. There are many ways to emulate classical OOP, but the most straightforward and the one designed into the language is this pattern. Only functions can have prototypes and prototypes hold instance methods. Then instances are new instances of the function which is now dubbed a constructor.

Prototypal OOP

I don't like the new keyword, it overloads the meaning of functions and is dangerous. If we were to say frank = Person("Frank"), then this inside the function would now be the global this object, not the new instance! The constructor would be overriding all sorts of global variables inadvertently. Also bad things happen if you return from a constructor function.

Instead try this on for size:

<prototypal-inheritance/prototypal.js#intro-to-style*>

Object.create is new to JavaScript (it's part of ES5), but node supports it so we can safely use it. This creates a new object that inherits from another object. Object.create actually can set properties right away, but the syntax is rather verbose:

<prototypal-inheritance/prototypal.js#object-create*>

There is more you can set, but value and enumerable are the interesting ones. What enumerable does is tell operators like for ... in if they should enumerate over that key. When you set a property directly, it's enumerable property is set to true automatically. Object.create actually defaults to false, so we could write this as:

<prototypal-inheritance/prototypal.js#object-create-ii*>

Just make sure you understand that most functions like sys.inspect and JSON.stringify won't show the name property of frank now that it's hidden. If you pass true as the second argument to sys.inspect, it will show hidden properties using Object.getOwnPropertyNames.

<prototypal-inheritance/prototypal.js#object-create-iii*>

Using Object.spawn

While Object.create is nice, it's still too verbose for my taste. On my projects I made a new function called Object.spawn. Here is the source for reference:

<prototypal-inheritance/spawn.js#object-spawn*>

Then you can create hierarchies of objects easily:

<prototypal-inheritance/spawn.js#animals*>

Using Object.prototype.spawn

Now that node supports Object.defineProperty, we can add methods to Object.prototype that are not enumerable and thus don't break stuff.

<prototypal-inheritance/spawn.js#proto-spawn*>

Which is used as:

<prototypal-inheritance/spawn.js#animals2*>

Where do we go from here?

I'm not sure if this is a good idea or not. You give up a lot by not having constructor functions that initialize state of objects. It could be baked into the Object.spawn method, but then you're dealing more with classical OOP emulations.

I plan on using this technique with some upcoming projects. I'm not sure what will come of it.