简体   繁体   中英

What is the purpose of “self.each(callback, array)” in the jQuery source code?

jQuery's .each function takes exactly one argument- a function. And yet, In this piece of jQuery code, we see the following:

if ( callback ) {
    self.each( callback, [ responseText, status, jqXHR ] );
}

Two args are being passed to .each . I'm assuming the values in brackets are params to the callback function, but I'm not clear on why this is possible and why someone would do this rather than calling the function directly? :

if ( callback ) {
    self.each( callback(responseText, status, jqXHR) );
}

"I'm not clear on why this is possible and why someone would do this..."

They wouldn't. It's for internal use only: https://github.com/jquery/jquery/blob/1.6.2/src/core.js#L248-253

// Execute a callback for every element in the matched set.
// (You can seed the arguments with an array of args, but this is
// only used internally.)
each: function( callback, args ) {
    return jQuery.each( this, callback, args );
},

This behavior could change at any time.


To be clear, normally your callback to each gets two arguments:

  • the i (property name or index) of the collection as the first

  • the value of the item at i as the second

But sometimes internally they want to use the each iterator, but they have no need for those arguments, and instead they want to substitute their own.

That's what's happening. You can see here that if the internal args property has been given a value, they do a slightly different iteration of the collection passing the args that were given.

So they do:

callback.apply( object[ name ], args )

...instead of:

callback.call( object[ name ], name, object[ name ] )

...or slightly something different but effectively the same for an Array-like collection.


You can test it on your own:

 // normal usage
$('p').each(function( a, b, c ) {

     // will show the index, the element, and undefined for each "p" element
    console.log( a, b, c ); 

});

 // internal usage
$('p').each(function( a, b, c ) {

     // will show 1, 2, 3 once for every "p" element
    console.log( a, b, c );

}, [ 1, 2, 3 ] );

But again, this behavior isn't for public use, and could change without warning.

RightSaidFred has answered part of this question – how the each call works. Here's why it's needed.

if ( callback ) {
    self.each( callback(responseText, status, jqXHR) );
}

That code won't work because it will call callback once, and then use the result of that as the argument of the each call. It is the approximate equivalent of

callback(responseText, status, jqXHR);
self.each ( true );

The next option is to do this with an anonymous function:

self.each (function() {
    callback(responseText, status, jqXHR);
});

This will work fine. However you have missing functionality. Your callback is run the correct number of times, but there is nothing to differentiate each iteration. You might as well do this:

for (var i = 0; i < self.length; i++) {
    callback(responseText, status, jqXHR);
}

By using each as the original code does, when callback is called, the relevant element in the array is used as the "context" – in practical terms, the value of this within the function. This means that the code can differ based on which element in the selection was passed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM