Question

Recently I started to learn a bit more advanced JavaScript (as far I only used jQuery for some simple tasks) and bought a book of Alex MaxCaw "JavaScript Web Applications". The first chapter treats about creating simple class emulator. I understand almost everything except for two lines of code marked with comments down below:

var Class = function(parent) {

    var _class = function() {
        this.init.apply(this, arguments);
    };

    if(parent) {
        var subclass = function() {};
        subclass.prototype = parent.prototype;
        _class.prototype = new subclass();
    };

    _class.prototype.init = function() {};

    _class.fn = _class.prototype;

    //????
    _class.fn.parent = _class;

    //????
    _class._super = _class.__proto__;

    return _class;
};

Can anyone tell me what is purpose of these two lines? I'll be very thankfull.

Was it helpful?

Solution

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 the init function called with the proper this 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 its prototype 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 an init function when you create a Class... or allow the instance to walk the prototype chain to look for other init 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 to prototype 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 get bind, apply, etc. _super in this case is just a reference to Function.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.called 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.

OTHER TIPS

From what i know, fn is just an alias to the prototype property

And about the _super, that one is for referencing to the "class" from which you are inheriting

Here's more about the use of _super and js inheritance: article

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top