My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Friday, January 18, 2013

Have You Met Empty ?

The proper title for this post could have easily been something like JavaScript Inheritance Demystified or slightly less boring as The Untold Story About JavaScript Objects ...well, thing is, I don't really want to alarm anyone about this story and as a randomly improvised storyteller, let's move forward, and see where it goes, starting from where it all began ...

Elementary, My Dear Watson!

The very first thing we might want to do, in order to make our research, discovery, and piece of programming history useful, is creating a couple of shortcuts that will let us easily analyze the code and the current story:
// retrieve the first inherited prototype
var $proto = Object.getPrototypeOf;

// retrieve all own properties,
// enumerable or not, ES5 stuff !
var $props = Object.getOwnPropertyNames;
Why do we need that? Because almost everything is an instanceof Object in JavaScript world, which simply means, and we'll see this later on, that Object.prototype is inherited all over!

Well, Almost!

Since Object.prototype is an object, there's no way this can be called as a function, right?
No doubts Object inherits at some point its own prototype but who added apply, bind, call, constructor, length, name, and that funny toString behavior in the middle?

Not Function !

That's correct, Function has nothing to do with that. Function actually inherited those properties and redefined some behavior such name and length.
Is the Object constructor instanceof the Function one ? Yes! Is the Function object instanceof Object ? Yes again and trust me: there's no real WTF!
Object instanceof Function; // true
Function instanceof Object; // true

The First Object Ever: null

This is the prototype of the prototypes, if we check $proto(Object.prototype) the result will be null indeed.
As summary, the very number one object to inherit from, possible in fact as Object.create(null) instance too, is this reserved static keyword everybody ever complained about because it returns "object" instead of "null" under typeof null inspection.
Can we start seeing that being the mother and the father of everything we use in JS world, "object" is kinda the best typeof we could possibly expect?

There Are Two Suns!

This is the lie we all believed until now, Object.prototype is where everything inherits from ... well, brace yourself, an hidden Empty object is part of this game!
Chicken or egg, who came first? You cannot use much philosophy in programming, you have to solve stuff and give priority or order to the chaos represented by requirements and/or implementations about specs, right? :D
So here the chain you have always wondered about:
null <
  Object.prototype <
    Empty <
Wait a second ... how can Object.prototype then exists before Object is even created ?
So here the secret about JavaScript, the elephant Classic OOP guys keep ignoring in the room: Object.prototype is just an object that's inheriting from null!
The fact we call it Object.prototype is because that's the only way to reach it via JavaScript but here how you could look at the story:
null: the omnipotent entity, the origin of everything,
      the daily Big Bang that expands on each program!

  prototype: like planet Earth,
             the origin of all our user definable problems

    Empty: the supreme emptiness of everything,
           meditation over "dafuq just happened"!

      Function: somebody has to do actually something concrete:
                the slave!

      Object: somebody has to take control of everything:
              the privileged king!
Are we done here? ... uh, wait, I knew that!
"The time has come," the Object said,
"To talk of many things:
Of keys and __proto__ and magic things
Of prototype and kings
And why that Empty is boiling hot
We show that pigs have wings."

The Object.prototype we set!
As prototype itself!
Object.prototype = prototype;

The instanceof Operator

As shortcut, instanceof is freaking fast compared with any user definable interaction with the code.
In few words, if you want to know if ObjA.prototype object is in the prototype chain of objB, you better objB instanceof ObjA rather than ObjA.prototype.isPrototypeOf(objB), I mean .. really, check performance here!

So, once we get the pattern followed by instanceof, it's easy to do the math here:
Object instanceof Object
// means
Remember the hierarchy? Object inherits from Empty, and Empty inherits from prototype so, of course Object inherits from prototype, it's transitive!
Object instanceof Function
Again, Object inherits from Empty so obviously Function.prototype, which is Empty indeed, is one of the prototype of Object ^_^

Who Defined The prototype Behavior?

This is the tricky one ... so, prototype is not even invocable and as such it cannot be used as constructor. Actually, neither can Empty, since it cannot be used as constructor too ... so new Empty will throw, watch out!
In fact, Empty introduces the [[Call]] paradigm, inherited by all primitive constructors such Array, Object, Function, Boolean, but is not inheritable from user defined objects, or better, you need to create a function(){} object to have that special behavior inherited from Empty and the prototype inherited from Function.
Empty.isPrototypeOf(function(){}); // true

Which prototype Behavior ?

Well, this is the main point about instanceof and isPrototypeOf(), the prototype behavior defined in the Function object, the only object adding that prototype property defining its behavior in the program!
["apply", "bind", "call", "constructor", "length", "name", "toString"]

["length", "name", "prototype"]
// could be more in other engines

The Last Troll Ever!

It's clear that Empty introduced the constructor property too and guess what happened there?
"The time has come," the Empty said,
"To talk of many things:
Of constructor and new toString
Of call, bind, apply and kings
And why that caller is boiling hot
We show that pigs have wings."

The Empty.constructor we set!
The Function we just let
So that Function.prototype(aka:Empty).constructor === Function is true :)
Last, but not least, if you think as "Empty function" Empty is fast, just check this bench and realize that it could be the slowest function ever invoked!
So, here is the story of the root of all amazing things we can enjoy on daily basis in this Internet era, could you imagine?

No comments: