Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding jQuery return object

I'm trying to understand how jQuery creates the return object when searching for DOM elements. I've gone through the source, but I'm not completely sure I understand, and was hoping somebody here could give me some insight.

From what I can gather reading the source, when querying for a jQuery DOM, jQuery finds matching DOM elements, and then adds the matched DOM element as an object using the index of the element as the key for the new object.

if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
    for ( match in context ) {
       // Properties of context are called as methods if possible
       if ( jQuery.isFunction( this[ match ] ) ) {
             this[ match ]( context[ match ] );    
            // ...and otherwise set as attributes
       } else {
            this.attr( match, context[ match ] );
       }
    }
}    
return this;

Returning this, is returning the entire jQuery object which includes all the methods. Have I got it right to this point?

Now, it appears all the functions like css,find,ajax,hide,etc. are in the jQuery.fn object.

Somehow (and I think this is where I'm not seeing it), these functions are called, not on the DOM element itself, but through the access.js https://github.com/jquery/jquery/blob/master/src/core/access.js

var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {

using css as an example, we have

jQuery.extend({
    css: function( elem, name, extra, styles ) {...

jQuery.fn.extend({
css: function( name, value ) {
        return access( this, function( elem, name, value ) {
            var styles, len,
                map = {},
                i = 0;

            if ( jQuery.isArray( name ) ) {
                styles = getStyles( elem );
                len = name.length;

                for ( ; i < len; i++ ) {
                    map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
                }

                return map;
            }

            return value !== undefined ?
                jQuery.style( elem, name, value ) :
                jQuery.css( elem, name );
        }, name, value, arguments.length > 1 );

What I think I'm missing is how did we get from calling $('div').css(...) to that calling the jQuery.fn.extend.css method, and from there, the access method being called with a different signature to the access method initialized in the core jQuery?

Also, if we're constantly replacing the jQuery[0],jQuery[1], how is it that I can have:

var divs = $('div');
var spans = $('span');

Maintaining two different set of document tags if they are both returning the same jQuery object? I thought the object would be updated.

Am I completely misunderstanding how this is all working?

like image 424
pedalpete Avatar asked Apr 11 '14 09:04

pedalpete


1 Answers

From what I can gather reading the source, when querying for a jQuery DOM, jQuery finds matching DOM elements, and then adds the matched DOM element as an object using the index of the element as the key for the new object.

Yes. jQuery instances are basically array-like objects.

if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
    for ( match in context ) {
       // Properties of context are called as methods if possible
       if ( jQuery.isFunction( this[ match ] ) ) {
             this[ match ]( context[ match ] );    
            // ...and otherwise set as attributes
       } else {
            this.attr( match, context[ match ] );
       }
    }
}    
return this;

But that's not what happens in this cited section of the code. What you see here is the code for handling the jQuery(html, attributes) signature - when the second argument is an object and the first is standalone html tag, then call the respective methods or set the attributes on the new collection (this).

Returning this, is returning the entire jQuery object which includes all the methods. Now, it appears all the functions like css,find,ajax,hide,etc. are in the jQuery.fn object.

Yes. The objects that are returned by the jQuery constructor do inherit these methods from the $.fn prototype object.

Somehow (and I think this is where I'm not seeing it), these functions are called, not on the DOM element itself, but through the access.js https://github.com/jquery/jquery/blob/master/src/core/access.js

access is just an internal helper function. All the jQuery methods are called on jQuery instances.

using css as an example, we have

jQuery.extend({
    css: function( elem, name, extra, styles ) {...

jQuery.css() is just a "static", internal helper function for getting computed css values. Nothing you'd ever directly use yourself.

jQuery.fn.extend({
    css: function( name, value ) {
        return access( this, function( elem, name, value ) {
            …
        }, name, value, arguments.length > 1 );
    }

What I think I'm missing is how did we get from calling $('div').css(...) to that calling the jQuery.fn.extend.css method

There is no jQuery.fn.extend.css method. That call to jQuery.fn.extend() does define the jQuery.fn.css method. And that's just the method you call - it's prototypically inherited by $('div').

and from there, the access method being called with a different signature to the access method initialized in the core jQuery?

No, why do you think that?

// the signature:
access = function( elems, fn, key, value, chainable, emptyGet, raw )
// the call:
access( this, // array-like collection
        function(…){…}, // callback
        name, // string
        value, // whatever
        arguments.length > 1 // boolean whether it's a getter
        // undefined, implicit
        // undefined, implicit
      )

Also, if we're constantly replacing the jQuery[0],jQuery[1]

No, we aren't? Where did you see that?

how is it that I can have: var divs = $('div'); var spans = $('span'); Maintaining two different set of document tags if they are both returning the same jQuery object?

They aren't. Both calls do create new jQuery instances.

I thought the object would be updated.

No, jQuery instances are quite immutable.

like image 117
Bergi Avatar answered Oct 11 '22 17:10

Bergi