5

With jQuery.each(), I can iterate through members of the array:

// This is NOT what I am looking for.
$('.example a').each(function() {
    // do a lot of things here
    $(this).css('color', 'red');
});


However, I need to apply a function to the jQuery array itself, and not to its members. So I wrote a little plugin to do this:

$.fn.all = function( callback ) { return callback.call( this ); }

$('.example a').all(function() {
    // do a lot of things here
    $(this).css('color', 'red');
});


Please notice that in the function above, this will be set to the collection of the elements - which is what I require.
Now I'm sure that jQuery should have an elegant way to do this, but I haven't found anything in the documentation, or by Googling.

Is it possible, and if it is, how do I achieve this without using custom plugins?

UPDATE: I can not do $('.example a').css('color', 'red'); directly. I have a dozens of calculations in the function, so I have to use something similar to the plugin I wrote. I am asking for a callback. The correct answer must provide a callback similar to the custom function.

5
  • What does "apply a function to the jQuery array itself" mean, exactly? Commented May 6, 2016 at 20:47
  • @Oriol He probably meant as a whole and not one by one. Commented May 6, 2016 at 20:48
  • .each applies a callback to each member of the array through iteration, so "this" will be the members of that array. What I need is that "this" will be the array itself, not its members. Please read the updated question. Commented May 6, 2016 at 20:52
  • "The correct answer must provide a callback similar to the custom function" Do you mean 1) a callback when all functions have completed; 2) 2) callback when each of the the functions have completed; or 3) both 1) and 2)? Commented May 6, 2016 at 20:57
  • No, maybe using the word 'callback' is not quite right. I need to apply the function to the array, and the this variable inside the function's scope should be referenced to the jQuery array. Please see my own custom function to understand what I want. Commented May 6, 2016 at 21:01

6 Answers 6

4

You don't need a plugin, you can use call directly:

(function() {
  // do a lot of things here
  this.css('color', 'red');
}).call($('.example a'));

Or consider passing the array-like object as an argument

(function(arrayLike) {
  // do a lot of things here
  arrayLike.css('color', 'red');
})($('.example a'));

Or if you prefer a jQuery way

$.each([$('.example a')], function(){
  // do a lot of things here
  this.css('color', 'red');
});
Sign up to request clarification or add additional context in comments.

2 Comments

This is a very elegant way to this, and I upvote it. However, I pretty much rather that I use the $(...).something format, because of the way it is currently formatted.
Then adding the method to $.fn seems the correct approach.
2

Shouldn't

$('.example a').css('color', 'red');

be enough?

5 Comments

It should, other than that I have more than a .css() in there, and all of them needs to be a) in a function b) done at the same time
@DRSDavidSoft, It is not possible in JS to execute more than one command/function at a time; so ... what?
I think I'm a bit unclear. As I said, I want to execute the action to the array itself, not to execute the action to all of its members at once. jQuery by itself allows a certain action to be done on the selected elements, for example $('a').hide() does have exactly the same results as $('a').each(function() { $(this).hide() }), however the latter would be slower. But as you can see, .hide() is done to all of the links at once, instead of iterating through the members and doing the action one-by-one. I hope it's clear.
@DRSDavidSoft Wouldn't $('a').hide() be implicitly doing an each?
@PatrickGregorio I've tried it many times, and it seems that either it does not do an each, or it does it so much better than passing a callback function to do it foreach element. Either way, I need the better performance here.
2

That would be the straight-forward (jQuery-esque) way to do what you want:

var $collection = $('.example a');
$collection.each(function() {
    // do a lot of things here
    $collection.css('color', 'red');
});

//And another reason I dislike jQuery's implementation of each().
//but most of all, wrong argument-order and the abuse of this to pass the current value/node

Here my prefered implementation. Mostly like Array.prototype.forEach(), and the nice parts of $.each().

$.fn.forEach = function(fn, scope){
    if(scope != null) fn = fn.bind(scope);
    for(var i = 0, len = this.length; i < len; ++i)
        if(false === fn(this[i], i, this)) break;
    return this;
}

and your code would be like:

$('.example a').forEach(function(node, index, $collection){
    //and don't use `$(this)`, since `this` most of the time references `window`
    //unless you've bound the function to a scope, or passed one to forEach

    var $node = $(node);

    $collection.css('color', 'red');
});

1 Comment

While still using a custom $.fn method, this is by far the best and most-detailed forEach implementation I have ever seen. Also, +1 for the "this abuse" part, can't express how much I agree!
0

this

$('.example a')

returns collection of matched elements. And this

$('.example a').css('color', 'red');

sets color red to all elements in the collection.

That's how jQuery works.

1 Comment

Sorry, I forget to mention that I don't just do a .css() in there. Please read the updated question.
0

I think that is not possible getting all the calculations at the same time, you should use threads for that, or a webWorker. You can get more info about this in mdn.

2 Comments

Thank you, but actually I need the callback to be linear instead. Your answer does not solve my problem, but it is a great article to read nonetheless.
I don't use foreach because it applies the function "for each" element. e.g: $els[0].doFunc(); $els[1].doFunc(); $els[2].doFunc(); ... But I require that the function be applied to all of the elements at the same time: $els.doFunc();
0

You can cache selector, utilize $.queue()

var elems = $(".example a");
$.queue(elems, "q", function() {
  $(this).css("color", "red");
  console.log(this)
});
$.dequeue(elems, "q")
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div class="example">
  <a href="#">a</a>
  <a href="#">b</a>
  <a href="#">c</a>
</div>

4 Comments

While not directly what I asked for, this is a pretty useful way to define queues, and I'm glad I learned it today. Thank you!
@DRSDavidSoft "While not directly what I asked for" Why included comments referencing $.when(), .then(). Was not certain what "I have a dozens of calculations in the function" was?
But this is using map, which iterates over the elements as a foreach, so you are not dealing with the array, only with the elements inside. Or am I wrong?(which s very possible)
This is the closest thing to a native jQuery method (which I asked for), however using queues are not necessarily required (which I didn't ask for), hence the sentence. I'm grateful nonetheless, as I am already using the example you provided in other parts of my code. Thanks again, and sorry if I were somewhat unclear with my question, but learning jQuery queues certainly makes life easier.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.