2

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')?

moey
  • 10,587
  • 25
  • 68
  • 112

4 Answers4

3

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.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • so its basically the same thing...more than explaining it,you have confused it..hope there is an simpler way of knowing it.. – HIRA THAKUR Sep 03 '13 at 09:25
2

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.

icktoofay
  • 126,289
  • 21
  • 250
  • 231
  • [`$.fn` is actually `$.prototype`](https://github.com/jquery/jquery/blob/master/src/core.js#L81) so the *will become properties* bit isn't entirely accurate. – mu is too short Oct 02 '12 at 03:57
  • can i get a bit of detailing..i got completely confused by reading what jfriend00 has written..your answer is clear but needs some detailing – HIRA THAKUR Sep 03 '13 at 10:01
  • @VAGABOND: I added some more detail that hopefully should help. I noticed that you edited my answer beforehand to add paragraph breaks and inline code blocks; if you do that again in the future, kindly make sure that what you're wrapping in code blocks actually is code (e.g., you put “object” and “instance” in code blocks, which are technical terms, but aren't code per se). – icktoofay Sep 04 '13 at 05:01
  • @icktoofay:no no no...you got me wrong,i understand the part that you explained.Any ways thx for the answer... I posted a question yesterday,have a look if you might be interested http://stackoverflow.com/questions/18590526/behind-the-scenes-of-jquery-fn-something-and-jquery-something – HIRA THAKUR Sep 04 '13 at 08:48
0

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.

jahroy
  • 22,322
  • 9
  • 59
  • 108
0

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

zzzzBov
  • 174,988
  • 54
  • 320
  • 367