JavaScript Classes and Instantiation Patterns

JavaScript's idiosyncrasies can be a bit frustrating, and functional classes are no exception. The language implements functional classes (aka constructor functions) as a critical technique for generating multiple objects with similar properties and methods. The four styles utilized to implement functional classes are functional, functional-shared, prototypal, and pseudoclassical. Mastering all four can prove to be an unnecessarily complicated endeavor, as each approach levies a unique interface with differing approaches to object construction. The fantastic news is that under the hood all four constructor function styles are doing basically the exact same thing. The quick reference below (Download @2x) demonstrates these strong similarities to hopefully eliminate confusion between styles.

In the example above, every house on the street needs to have a color, a door, and methods to open and close the door. Functional classes are perfect here because every instance created by the function will have these basic desired attributes, so we can quickly create thousands of homes. Each functional class style performs the same basic steps to help us generate all these new homes:

  • generate an object
  • assign some properties
  • add some methods
  • return that object

It's so simple! So, why even confuse the matter with four different styles? Each one has its pros and cons. It all boils down to readability and techniques to prevent unecessary method duplication.

The clarity of the functional style is unmatched, with object generation, property and method assignment, and object return all right before your eyes. This is a great place to start when first diving into functional class styles. However, given the tremendous variation in utilization across the industry, it's wise to master each and understand why modern frameworks have gravitated toward pseduoclassical style. The biggest setback of the functional style is that our methods will be duplicated for every object created. That means a new function, stored in a new spot in memory, every time we generate an object; not perfect.

Functional-shared helps alleviate those concerns by utilizing a single repository for our methods, and then generating pointers each time we create an object. In the example above, every new object will point back to the houseMethods object where these shared functions are stored a single time in memory. Awesome, now we are saving space! Still, setting these method pointers can be less efficient than delegating through fallback.

So what are fallbacks? Fallbacks are a back-up plan for objects, essential to the prototypal style. If a method (or property) is called on an object, and that method doesn't exist, JavaScript will check if it's defined on this fallback object. Fortunately, every function has a property called "prototype" where these fallback methods are typically stored. In the prototypal's House function, we explicitly delegate the House function's "prototype" property (House.prototype) as the fallback location for EVERY house object created by House. Now every method in House.prototype is available to every object created by House, without duplicating methods in memory! You can set anything as the fallback too, like our old houseMethods object, and this is specified via the input to Object.create(). The prototype property on the constructor function just happens to be the most organized location to delegate fallback.

Lastly, pseudoclassical attempts to wrap all this goodness in the most concise presentation possible. Rather than assign Object.create(House.prototype) to a new variable, the pseudoclassical style simply assigns it to "this" for simple property assignment and method creation. And to top it off, the interpreter will do this automatically behind the scenes, along with returning the object, as long as the keyword new is utilized at instantiation time var house = new House('red'). The remaining code is clean and concise, but can be tricky to reason with before developing a complete understanding of this syntactic sugar.

So how does instantiation fit into this class debacle? Instantiation takes place when a functional class is utilized to create a new object, var house = House('red') in the examples above. Pseudoclassical is the only class that takes advantage of the new keyword (detailed above), while the rest of the classes are used like any other function call.

It absolutely makes sense to run with the style that works best for you. Still, if you come across any pattern and are still confused, check out the quick reference for a refresh on the subtle differences. Best wishes on your utilization of the four class styles. A quick dive into subclassing is soon to follow!