Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the jQuery constructor map to jQuery.fn.init? [duplicate]

The jQuery constructor sort of maps its functionality to another constructor, jQuery.fn.init:

jQuery = function( selector, context ) {
    return new jQuery.fn.init( selector, context, rootjQuery );
},

I'm wondering why.

This question is very similar, but even the answerer admits they didn't really answer the question as to why

This question is still unanswered

Is this just for organizational purposes? Rather than putting the init function inside the jQuery constructor definition, maybe the authors wanted to package it.

Is there any reason to have the .init() method on the prototype? I don't think anyone ever uses $('.something')...init()...

This question shows that its not necessary to have .init on the prototype.

And I just found this question in which Dan Herbert's answer suggests that it is simply for structure/readability purposes.

In conclusion, can I confirm that this constructor/prototype mapping funny-business is kind of unnecessary? It seems to me that the jQuery.fn.init functionality could go:

  • Anywhere in the closure
  • On the jQuery object (jQuery.init vs jQuery.fn.init)
  • Or, what makes most sense to me: directly inside the jQuery function/constructor definition, replacing new jQuery.fn.init and avoiding the jQuery.fn.init.prototype = jQuery.fn mapping.
like image 714
Michael Lewis Avatar asked Nov 03 '13 22:11

Michael Lewis


People also ask

What does jQuery FN init mean?

fn. init() {...} , is given the jQuery prototype so that its object 'type' is of jQuery , and that all instances of it are actually instances of jQuery .

What does FN do in jQuery?

fn is an alias for jQuery. prototype which allows you to extend jQuery with your own functions.


1 Answers

The jQuery constructor sort of maps its functionality to another constructor

The fact is that jQuery is not really a constructor function and shouldn't be seen as one either. By definition, a constructor's responsability is to initialize instance properties, which is not really the case with jQuery. Also, calling new jQuery() would be non-sense. jQuery is a factory function for creating jQuery.fn.init instances, nothing more.

Now, perhaps you are wondering why they simply didin't use jQuery as a real constructor?

Well because they did not want a constructor that we call with new all the time, they wanted a factory function. That's fine with me, however where I tend to disagree is that their pattern is very cryptic and doesn't quite reflect the intention.

It would have been far better in my opinion to chose better names:

function jQuery(selector, context) {
    return new jQuery.Set(selector, context);
}

jQuery.Set = function (selector, context) {
    //constructor logic
};

//allows syntaxic sugar
jQuery.fn = jQuery.Set.prototype = {
    constructor: jQuery.Set,
    //methods
};

I've pretty much only remapped jQuery.fn.init to jQuery.Set and it suddenly all makes more sense to me. When looking at the code above, it's easy to see that:

  1. jQuery is a factory function for creating jQuery.Set objects.
  2. jQuery.fn exists only as a syntaxic sugar, instead of having to write jQuery.Set.prototype all the time to modify the prototype.

Now, in the source we also see that they do the following, which is kinda non-sense since jQuery is not the real constructor, it's jQuery.prototype.init and since we aren't creating jQuery instances, setting jQuery.prototype seems useless:

jQuery.fn = jQuery.prototype = {
      constructor: jQuery

One of the reasons behind this is certainly that they want to accomodate people that might modify jQuery.prototype instead of jQuery.fn.

However another valid reason is that they perhaps wanted somejQueryObj instanceof jQuery to returns true, while it normally wouldn't. If you take the pattern above (with jQuery.Set) you will notice that:

jQuery() instanceof jQuery; //false
jQuery() instanceof jQuery.Set; //true

However if we set the prototype of jQuery to jQuery.Set.prototype, let's see what happens.

jQuery.prototype = jQuery.Set.prototype;
jQuery() instanceof jQuery; //true!

It's not easy to understand eveything that led to those design decisions and perhaps I am missing important points, but to me it seems their design is overcomplicated.

like image 174
plalx Avatar answered Oct 24 '22 22:10

plalx