Breaking the MagiJSian’s Code: JavaScript Object Creation Patterns, Revealed!
A famous American illusionist recently floated into the sky.
It was an impressive feat, but let us not forget how much (ahem..) groundwork was put in over the years prior. Standing (or hovering) on street corners, year-on-year, he focused on his fundamentals: creating objects from thin air.
Let us become magician programmers and explore the mighty powers available to us for making new JavaScript objects.
Basic Sleight of Hand: `Object.create`
The trick to trump all tricks: Create a brand new object; link it to another object. Behaviour delegation is what JavaScript ‘inheritance’ is really all about.
When the property cannot be found on the object in question, it delegates to the next object up the prototype chain.
Watch and learn:
There is a catch (although it’s really a feature). Sometimes your new objects will have hidden properties that you forgot were lurking in the background. To create a truly new, shiny object, you will need to pass null
to Object.create
(like so…)
For my next trick I will need a blank piece of paper:
Having built in methods that all objects can access turns out to be a useful feature, and so in JavaScript objects typically delegate, in the last instance, to Object.prototype.
This is a special object that we could call ‘the prototype of prototypes’.
What is Object.prototype
's prototype? null
:
Object.getPrototypeOf(Object.prototype) === null // true
ES6 Classes
Of course, to be a modern magician, you’ve got to have class. Since ECMAScript 2015, we’ve had access to a new kind of syntax for constructing objects: the class
keyword. We also were given the extends
keyword, for emulating traditional class inheritance and creating a superclass/subclass relationship.
Except… in JavaScript there aren’t really any classes! But there is now a way to dress up the basic sleight of hand object creation into something a little more… classic. If it makes it easier to digest for you, then use this syntax, but to know what it’s really doing under the hood we need to hark back to pre-ES6 object creation patterns…
Pseudo-Classical
Harry Houdini is trying to prepare his next illusion. He’s getting tired of repeating the same props, but he also doesn’t want to make everything from scratch.
In steps the new
keyword! We can use it with a function that was made specifically to create new objects, a constructor function (we capitalise the name of this function, by convention).
If we instead don’t want to bother with resetting constructor
property, the pattern breaks down as:
function Constructor() {
// Add properties you want to be unique to an object
}Constructor.prototype.propertyName = // a shared property;Constructor.prototype.methodName = function() { // a shared method }
But we could also add properties to the prototype from within the constructor function, using conditional branches to prevent duplication of code:
function Constructor() {
// Add properties you want to be unique to an objectif(!this.propertyName) {
Constructor.prototype.propertyName = // shared property;
}
if(typeof this.methodName !== 'function') {
Constructor.prototype.methodName = function() { // shared method }
}
// We checked if the properties/methods existed on 'this', (or a prototype in 'this's prototype chain).
}
But what is this
? You might be wondering. Let’s delve deeper into the secrets of the constructor function:
When a function is called with new,
it:
a) Creates a new object
b) Creates a prototype linkage from the new object to the object referenced by the prototype
property of the function.
(So far, it’s done what Object.create
does, but it also…)
c) Binds the object to the this
keyword (which changes the execution context of the function)
d) Implicitly returns the object from the function call
One last point… how do we know if the properties of our object come from its prototype?
Objects Linked to Other Objects (OLOO)
Phew! Old Houdini had to put up with a lot of complexity. A modern mage realised this and came up with a new trick harnessing the power of Object.create
in a different way.
The pro’s and cons of this pattern have been (and will continue to be) thoroughly debated. One aspect that changes with this pattern is how to identify the prototypal inheritance (or behaviour delegation) at play:
That does it for this edition of… ‘Breaking the magiJSian’s code’