views:

446

answers:

3

Trying to understand how jquery works under the covers, what's the difference between:

jQuery.fn and jQuery.prototype

jQuery = window.jQuery = window.$ = function( selector, context ) {
     // The jQuery object is actually just the init constructor 'enhanced'
     return new jQuery.fn.init( selector, context );
},

and then:

jQuery.fn = jQuery.prototype = {
    init: function( selector, context ) {
+3  A: 

The first code snippet you've given is what creates the jQuery object in the first place (as objects in javascript are just functions).

Then, in the second snippet, jQuery.fn is set to be an extended version of the jQuery object itself, containing all the actual methods. It is extended using the prototype property, which doesn't have to do anything with jQuery itself.

http://mckoss.com/jscript/object.htm on Javascript OOP

Hope that helps...

x3ro
+7  A: 

The first snippet guarantees that your use of jQuery will always call the init function on jQuery's prototype.

$() == jQuery() == new jQuery() == new jQuery.prototype.init()

The second snippet allows you access jQuery's prototype from fn. By assigning functions to the fn property, they're also being assigned to $.prototype. This allows these methods to be called on objects returned from $:

jQuery.fn.example = function() { alert(this.id); }
$('#some-id').example(); // alerts 'some-id'
seanmonstar
why is it jQuery.fn.init and not just jQuery.init ?
mrblah
to be honest, I don't know why they made that decision. It provides no advantages to simply jQuery.init.
seanmonstar
Wouldn't it be so that the init() method itself is part of that prototype, and is therefore available on all jQuery instances.
thomasrutter
+1  A: 

jQuery.fn is the prototype upon which all new instances of jQuery are based. It exists so that third party code (and jQuery itself!) can extend jQuery using code like this:

jQuery.fn.myMethod = function() {...}

However, currently in jQuery, all the following four are references to the same object!

  • jQuery.fn
  • jQuery.prototype
  • jQuery.fn.init.prototype
  • jQuery.prototype.init.prototype

And that's not all: since jQuery and $ are (usually) aliases of each other, you can substitute jQuery for $ in any of the above, making 8 references to jQuery.fn.

So why have they given the same thing all those different names? Partially historical, partially necessary for prototypal inheritance.

jQuery.fn is pretty important, because both jQuery itself and lots of existing code rely on referring to it that way when extending jQuery, so that's why that's there. It's also nice and short which makes it a bit more friendly to type and read back than the other two, though I must say that the name 'fn' is confusing to me.

As for jQuery.prototype, once that reference is created it's never referred to in jQuery itself, so it's not clear what it's doing there. With knowledge of prototypal inheritance you may think that it's there so you can use jQuery with the new operator like this:

obj = new jQuery(selector);

but the jQuery() constructor does not use the new object that would be created inside it, and instead returns an object created elsewhere - in jQuery.fn.init() in fact. jQuery.prototype is not needed. Presumably, it's there for third party compatibility - so third party code can use jQuery.fn and jQuery.prototype interchangeably.

Which brings us to jQuery.fn.init.prototype. This reference is needed because it serves as the prototype for the jQuery.fn.init() constructor. It's in this constructor function that the actual creation of new jQuery objects happens, and in this case they are created using prototypal inheritance, which refers to a property of the constructor called 'prototype' when creating a new object, giving that new object to the constructor as the 'this' keyword.

Lastly, jQuery.prototype.init.prototype is just a crazy consequence of having jQuery.fn and jQuery.prototype referring to the same thing. You wouldn't use it.

Note that the following 4 expressions are all equivalent in jQuery, even though they might not be all be the recommended way. All these return a new object which uses jQuery.fn as a prototype - in fact all of these call jQuery.fn.init() as a constructor. And don't forget you can usually substitute jQuery with $.

jQuery()
new jQuery()
new jQuery.fn.init()
new jQuery.prototype.init()

jQuery tends to offer a lot of different ways of doing the same thing, or even referring to the same method or property. I guess you could say this about the browser APIs or the DOM too. But it's bound to make the task slightly more difficult for jQuery's developers who need to make sure future releases are backwards compatible.

thomasrutter