Reputation: 10887
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
Reputation: 129001
When you do something like var el = $("#content");
, you're dealing with a few different types of objects:
"#content"
. 'Nuff said.$
(here, a synonym for jQuery
) is a function. You're calling it with the string "#content"
, as we established above.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
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
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
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