views:

395

answers:

3

I try to create some class based-on jQuery style like the following code.

myClass = window.myClass = function(x, y)
{
    return new myClass.fn.init(x, y);
};

myClass.fn = myClass.prototype = 
{
    init: function(x, y)
    {
        // logic for creating new myClass object.
    }
};

I do not understand why jQuery use new keyword for creating its class because from my experiment, JavaScript always create myClass.init object instead of myClass object. However, I try to remove new keyword in myClass constructor. But it still not changes. Can you explain why jQuery can do that but I can’t or give me some code for using in init function?

By the way, I can use the following code instead of jQuery style code for creating the same object. What is the different between my code & jQuery code? Are there any benefit for using jQuery style?

myClass = window.myClass = function(x, y)
{
    this.init(x, y);
};

myClass.fn = myClass.prototype = 
{
    init: function(x, y)
    {
        this.x = x;
        this.y = y;
    }
};

PS. I like write code that separate initial logic into function because it is very easy to override this function by other people that use my code like my following code.

// override init function of myClass
myClass.fn._old_init = myClass.fn.init;
myClass.fn.init = function()
{
    // logic for doing something before init

    this._old_init();

    // logic for doing something after init
};

Thanks,

+2  A: 

This approach should work perfectly. One thing you may be missing is the fact that, using this technique, you're not going to be creating an instance of myClass; you're going to be creating an instance of myClass.prototype.init.

So, any methods defined in myClass.prototype won't be available to the instance. You'll want to make sure that the init's prototype points to myClass's prototype:

myClass.fn.init.prototype = myClass.fn;


FWIW, I don't see any real benefit in this approach. What's wrong with this? -

function myClass(x,y) {

    if ( !(this instanceof myClass) ) {
        return new myClass(x,y);
    }

    // Prepare instance

}

myClass.prototype = { /* Methods */ };

// It can still be overwritten:

var oldMyClass = myClass;

function myClass(x,y) {

    // Hack some stuff here...

    return new oldMyClass(x,y);
}
J-P
Your answer is true because I just found that jQuery use this statement (jQuery.fn.init.prototype = jQuery.fn) for giving the init function the jQuery prototype for later instantiation. However, your answer and your example do not solve my question why jQuery use this style for creating jQuery object.
Soul_Master
jQuery probably uses this technique to separate the constructor-functionality from the generic wrapper function (`jQuery()`). They could do it either way, it's probably a decision that was made very early on in jQuery's development and hasn't changed because it seems to work effectively...
J-P
@J-P - agreed that it's probably reminiscient of an early decision
Russ Cam
Perhaps this can shed some light: http://www.mail-archive.com/[email protected]/msg45575.html It's interesting that the author of `jQuery.fn.init.prototype = jQuery.fn` doesn't see its applicability outside of jQuery.
Crescent Fresh
A: 

I'm not entirely sure what the question is, but I'll do my best to answer what I think you're asking.

the new keyword is used to instantiate a new instance of the object returned by the function defined by the init property on the function prototype.

I believe the code is written in this fashion so that the new keyword is not required each time you instantiate a new jQuery object and also to delegate the logic behind the object construction to the prototype. The former I believe is to make the library cleaner to use and the latter to keep the initialisation logic cleanly in one place and allow init to be recursively called to construct and return an object that correctly matches the passed arguments.

Your second block of code does not return an object. Try it out in Firebug with

var myClass1 = myClass(1,2);
console.log(myClass1);

you get this.init is not a function error. The only way that this would work is if you use the new keyword as in

var myClass1 = new myClass(1,2);
console.log(myClass1);

Compare that with the code similar to that in jQuery

myClass = window.myClass = function(x, y)
{
    return new myClass.fn.init(x, y);
};

myClass.fn = myClass.prototype = 
{
    init: function(x, y)
    {
        this.x = x;
        this.y = y;
    }
};

var myClass1 = myClass(1,2);
console.log(myClass1);

var myClass2 = new myClass(1,2);
console.log(myClass2);

In each case, you correctly get an object returned with an x property with value 1 and a y property with value 2, whether the new keyword is used or not.

Russ Cam
I just tell you in my answer. My code in my question does not work when you do not use new keyword.
Soul_Master
It's not clear from the wording in your question that this is what you are stating
Russ Cam
A: 

The jQuery object initialization should like the following code.

jQuery = window.jQuery = window.$ = function (x, y)
{
    return new jQuery.fn.init(x, y);
};

jQuery.fn = jQuery.prototype = 
{
    init: function()
    {
        // some logic for object initialization
        return this;
    }
};

jQuery.fn.init.prototype = jQuery.fn;

The only one benefit of this code is it always create instance of jQuery object although you do not use new keyword for creating object.

In the other hand, my code that use init function for initialization object does not work if you do not use new keyword when call it. For fixing it, you must add some code like "J-P" example for checking this object. If type of it is not current class, it will automatically create instance for it.

Both of codes should work fine. But I like jQuery style more than "J-P" style because it is quite easy to read and modify.

Thanks,

Soul_Master