Walking through the code:
- Class is defined as a function that calls init with the arguments provided it. This means you can call it with standard constructor syntax using
new
eg.var instance = new Thingy()
and get theinit
function called with the properthis
value. - If you pass a parent class in, your class gets that class's
prototype
property added to the prototype chain of a new empty object which it uses as itsprototype
property. A more succinct way of doing this in modern browsers is_class.prototype = Object.create(parent.prototype);
- The
init
function is defined. This should likely be overridden with more useful initialization code after a_class
instance is created (or the code should be changed to allow the passing in of aninit
function when you create a Class... or allow the instance to walk the prototype chain to look for otherinit
functions. _class.fn
is created to provide a reference to the_class
constructor's prototype function._class.fn.parent
is created to provide a reference back to the constructor. This may be useful if you are applying the prototype in some other context and want a reference back to the prototype's constructor._class._super
is assigned the internal, non-standard__proto__
property of the constructor. Remember that constructors are functions and, in Javascript, functions are objects. This means they have their own internal prototypes. The earlier references toprototype
are the prototype assigned to objects created with this constructor NOT the constructor's prototype itself. All functions inherit from Function.prototype, which is where they getbind
,apply
, etc._super
in this case is just a reference toFunction.prototype
.
As to when this type of _super
is used, one could imagine doing the following:
function Maker(){ //this will be called as a constructor, ie. with new
var fun = function(){}; //Make a function
fun.__proto__ = this.__proto__; //yuck. Set the function's this value to the instance
return fun; //return the function
}
Maker.prototype={say:function(){console.log("Javascript is fun!.. And weird.")}};
var fun = new Maker();
fun.say() //"Javascript is fun!.. And weird."
console.log(fun.__proto__) // Object{say:function}
console.log(fun.bind) // undefined!!
Woah! What just happened?
In fact, you replaced your functions internal prototype with an Object. This allows you to build up interesting prototype chains and interact with both functions and objects in a similar way. Note, however, that the link with Function.prototype
has been severed, which is why we don't have access to bind
. However let's fix it with more prototype magic!
function FunctionConnector(obj){
for (var prop in obj){
if(obj.hasOwnProperty(prop){
this.prop=obj.prop
}
}
}
FunctionConnector.prototype=Function.prototype;
Maker.prototype=new FunctionConnector({say:function(){
console.log("Javascript is fun!.. And weird.")
}});
var fun = new Maker();
fun.say() //"Javascript is fun!.. And weird."
console.log(fun.__proto__) // Object{say:function}
console.log(fun.bind) // function bind(){ [native code] }
Now what is that FunctionConnector
? It takes an object and, when called as a constructor, returns an object that both has all the properties of the passed object AND inherits from Function.prototype
. As you can see, our access to bind
has returned (Of course we also could have made do with our original implementation and just Function.prototype.bind.call
ed our way to victory).
With this new pattern in hand it may be clearer what _super
in your code does, namely it references the built in prototype of the _class
constructor you are making (In our example the instance of FunctionConnector
would be _super
). This reference could be used to patch the prototype at runtime, call methods with apply
or anything else you can due with a reference to an object.
This is, as you may have noticed a little hackish, especially since __proto__
is nonstandard. But it's also somewhat neat if you enjoy the patterns it allows. I'd recommend only doing something like this if you are very confident in your knowledge of Javascript inheritance, and perhaps not even then unless you are in charge of your entire code base.