moey
moey

Reputation: 10887

jQuery fn Property

Using e.g. Chrome Developer Tools, we can easily inspect JavaScript / jQuery objects. I am trying to understand the following:

$.ajax    // defined as 'function ...'
$.fn.ajax // undefined

$.removeClass    // undefined
$.fn.removeClass // defined

Since $.removeClass is not defined, how come we can invoke e.g. $('body').removeClass('some-class')? And, this leads to an error $('body').fn.removeClass('some-class')?

Upvotes: 2

Views: 1627

Answers (4)

icktoofay
icktoofay

Reputation: 129001

When you do something like var el = $("#content");, you're dealing with a few different types of objects:

  • Strings. "#content". 'Nuff said.
  • Functions. $ (here, a synonym for jQuery) is a function. You're calling it with the string "#content", as we established above.
  • jQuery objects. The jQuery function creates jQuery objects. el is one of those objects.

The jQuery function and its direct attached properties are mostly things that don't apply to any particular element; they're things you might want to do on their own. Take, for example, jQuery.ajax; that doesn't apply to an element, so it was put directly on the jQuery function.

Other functionality only makes sense when you've got the context of what elements to apply the operation to. Say, for example, removing a class. If I say jQuery.removeClass("selected");, what do I want to remove the class from? You never specified, so you can't do that. Instead, assuming we assigned el as above, el.removeClass("selected"); does indeed make some sense; it removes a class from whatever elements el represents (here, the element with an ID of content).

Whenever we have one of these function names after the dot, it's a property of something before the dot (either directly or indirectly). In the case of functions like ajax where no elements are involved, it's put directly on $/jQuery. In the case of methods like removeClass, it's put on all jQuery objects.

Of course, if you ever want to add a new method that can be used on a set of elements like removeClass, it would be rather tedious to add that property to every single one, let alone the issue of getting a reference to every jQuery object, past, present, and future! For that reason, jQuery.fn is an object that acts as the prototype of all jQuery objects. That means that whenever you create a new jQuery object, it will act minimally like the prototype it was based on, jQuery.fn. If you add a property to jQuery.fn, it will appear on all jQuery objects. In fact, the concept of a prototype is deeply embedded into JavaScript, and modifying jQuery.fn will affect all jQuery objects, whether they're newly created, created in the past, or created in the future.

Upvotes: 2

jfriend00
jfriend00

Reputation: 707416

You are asking about two different types of objects.

$ is the same as jQuery and is a function that has properties on it. $.ajax is one of those properties.

An actual jQuery object as in what $('body') creates is actually an object that is an instance of jQuery.fn.init not of jQuery.

So, that's the first reason that you see different methods on $ and $('body') because they are different types of objects and thus can have different types of methods.


To understand further, the methods on $ (which is a synonym for jQuery) are the methods that are added directly to the jQuery function itself. In the jQuery code, this is mostly done with jQuery.extend() right on the jQuery object. $.ajax is one of those.

The methods on the jQuery object created by the jQuery function are the methods that are assigned to jQuery.fn.init.prototype which due to some trickery by jQuery are the methods assigned to jQuery.fn. As it turns out jQuery.fn.init.prototype is set to be the same object as jQuery.fn so when anything is assigned to jQuery.fn, it automatically goes to jQuery.fn.init.prototype and anything on that prototype automatically becomes a method of a jQuery.fn.init object which is what is created by the jQuery function such as jQuery('body') or $('body').

You can see this in action in the jQuery code. If you look at the jQuery function, it looks like this (it creates an object of jQuery.fn.init and thus will have the methods from jQuery.fn.init.prototype:

// Define a local copy of jQuery
var jQuery = function( selector, context ) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init( selector, context, rootjQuery );
},

And, then later the .fn is like this:

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

Which is how any method assigned to jQuery.fn is also on the jQuery.fn.init.prototype and becomes a method on a jQuery object.

Upvotes: 3

zzzzBov
zzzzBov

Reputation: 179086

When you declare a function in JavaScript, it is an object:

function foo() {...}
foo.bar = 'baz'; //set the `bar` property on `foo`

...as well as being a constructor:

var f = new foo();
f instanceof foo; //`true`
f.bar; //undefined

When you construct an object from a function, the instance will inherit properties from the prototype of its constructor function:

function Bar() {...}
Bar.prototype = {
    baz: function () {
        console.log('baz');
    }
}
var b = new Bar();
b.baz(); //logs 'baz'
Bar.baz(); //error

Additionally, objects in JavaScript are passed by reference*.

var fizz,
    buzz;
fizz = {};
buzz = fizz;
buzz.foo = 'bar';
console.log(fizz.foo); //logs 'bar'

the jQuery factory function (jQuery or $) is essentially** defined in the following way:

function jQuery(...args...) {
    //the map returned is a jQuery init object
    return new jQuery.init(...args...);
}
//jQuery.init is a function used as a constructor
jQuery.init = function () {...do stuff...};
//jQuery.init.prototype is an object containing the methods that can be called on
//jQuery.init objects
jQuery.init.prototype = {
    addClass: function () {...},
    on: function () {...},
    removeClass: function () {...}
};
//The jQuery.init.prototype object is exposed via jQuery.fn
jQuery.fn = jQuery.init.prototype;
//functions available on the jQuery namespace are added to the jQuery function object.
jQuery.ajax = function () {};
jQuery.extend = function () {};

* sorta
** gross oversimiplification

Upvotes: 0

jahroy
jahroy

Reputation: 22692

I'm very new to jQuery, but my understanding is that $.fn is a property that contains all methods that can be invoked on jQuery objects.

That's why when you write a plugin, you extend $.fn by adding your own function definitions.

Upvotes: 0

Related Questions