58

I know that it's faster to do the following:

var $header = $("#header");
$header.css({color:"#ff0000"});
$header.find("a").addClass("foo");

Instead of:

$("#header").css({color:"#ff0000"});
$("#header a").addClass("foo");

Because jQuery doesn't need to find the elements again in the DOM as we have direct reference to them.

Let's say that I have this:

var $header_elements = $("#header li");
var $footer_elements = $("#footer li");

And I use both individually for a few jQuery manipulations. But then, I need to do something on both. Using selector, I would do this:

$("#header li, #footer li").css({color:"#ff0000"});

But then, the DOM needs to be parsed again to find matching elements. Is there a way to use my previously declared variables instead of a new selector? Something like the following (which is not working, I know, it's to give an idea of what I'm looking for):

$($header_elements + $footer_elements).css({color:"#ff0000"});

I think that the selector returns some kind of array or object. What I'm looking for is a way to merge those. Anyone know if this is possible and how to do it?

Thanks for your help!

9 Answers 9

75

Just use the add method:

$header_elements.add($footer_elements).css({color:'#ff0000'});

Given a jQuery object that represents a set of DOM elements, the .add() method constructs a new jQuery object from the union of those elements and the ones passed into the method. The argument to .add() can be pretty much anything that $() accepts, including a jQuery selector expression, references to DOM elements, or an HTML snippet.

Sign up to request clarification or add additional context in comments.

3 Comments

Or to use his source examples: $header_elements.add($footer_elements).css({color:'#ff0000'});
Maybe not the fastest possibility according to the tests I did, but gnarf is right, it looks cleaner and in case where there are duplicates between the two "sets", it'll take care of it. Thanks!
For this case, add() is the correct function to use. Almost unexpectedly, add() does not permanently modify the jQuery collection. So, even after you add $footer_elements to $header_elements, references to $header_elements from that point on will only effect the original collection. $.merge, however, will permanently modify the first collection in the argument, so after $.merge($header_elements,$footer_elements), any action taken on $header_elements will effect the $footer_elements collection as well. - Example here: jsbin.com/osupi3/2/edit
24

Here is a solution:

$.merge($header_elements, $footer_elements).css({color:"#ff0000"});

I tested it with JS Fiddle here : http://jsfiddle.net/bgLfz/1/

I tested using selector each time, variable for both selector, variables with $.merge() and using .add(). Each test was run 1000 times.

Results on my side are as follow (from faster to slower):

  1. Using $.merge() (average of 7ms)
  2. Using both variable one after the other (average of 10ms but the code needs to be duplicated)
  3. Using .add() (average of 16ms)
  4. Using selectors each time (average of 295ms)

5 Comments

it will definitely be slower as jquery will have to merge the variables and then still go through them with each.
Merge will append directly to $header_elements though... Making it contain $footer_elements as well
See jsperf.com/adding-selectors for some simple performance testing... Also note, the function add() takes more time, but it also looks cleaner, and removes potential duplicates :)
@Raveren - Take a look at the jsperf - The "slowerness" is almost un-noticeable.
Performance isn't so much the issue here - the fact that $.merge() permanently modifies the first argument is a much larger concern( as gnarf pointed out). After the merge, $header_elements will now contain the $footer_elements collection, meaning if you just wanted to affect the header elements, you couldn't (without running the query again). Example is here: jsbin.com/osupi3/2/edit
15

You can use add or merge method:
Add

$header_elements.add($footer_elements).css({color:'#f00'});

merge

$.merge($header_elements, $footer_elements).css({color:"#f00"});

Both work, but add is more performant. enter image description here Source: http://jsperf.com/add-vs-merge

Credit: I upvoted @GenericTypeTea and @Gabriel answers, did a summary of both, compared them and here is the result.

1 Comment

are there any caveats when there are more than two variables being added or merged together? and what would the correct syntax be for such a scenario, eg: do you chain the add() methods like: $my_var_1.add($my_var_2).add($my_var_3).add($my_var_4) or does add() accept an array of variables like: $my_var_1.add($my_var_2, $my_var_3, $my_var_4)?
6

Pass an array of references:

$([$header_elements, $footer_elements]).css({color:"#ff0000"});

1 Comment

This would be my approach, but you can't pass jQuery objects in the array. You need to pass DOM elements. $([$header_elements[0], $footer_elements[0]])
3

It does not matter performance wise wether you'll do something like (even if it worked):

$($header_elements + $footer_elements).css({color:"#ff0000"});

or do them separately:

$($header_elements).css({color:"#ff0000"});
$($footer_elements).css({color:"#ff0000"});

as jquery will internally go through the supplied arguments using each().

If the principle is more DRY inspired, than performance wise, you can create a function:

function makeThemRed( el ) {el.css({color:"#ff0000"})}

and then

makeThemRed($header_elements);
makeThemRed($footer_elements);

or even:

function makeThemRed() 
{
   var l=arguments.length,
       o=0;
   while (o<l) {
       arguments[o++].css({color:"#ff0000"})
    }
}

and then

 makeThemRed($header_elements, $footer_elements); //any number of parameters

Comments

3

The thing with using 'merge' is that it's limited to just two selectors, and using 'add' will be so messy if it's more than two, so if it's more than two, you should use 'each' like this:

$([selector1, selector2, selector3, .....etc]).each(function(){
    // your code here
});

2 Comments

If you are going to answer a question almost 4 years after it's been posted, you should be absolutely sure that you are actually answering the question correctly and that your solution is better than the already accepted one. Your answer is not even close to answering the original question.
I thought the " original question " is somehow related to jquery ;) :D
2

To keep the code simple and prevent code duplication I used a forEach loop.

var $header_items = $("#header li");
var $footer_items = $("#footer li");

[$header_items, $footer_items].forEach(function($blockItems){
    // do logic here
    $blockItems.css('color', 'red');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="header">
    <h1>Header</h1>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
        <li>Item 4</li>
        <li>Item 5</li>
    </ul>
</div>
<div id="footer">
    <h1>Footer</h1>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
        <li>Item 4</li>
        <li>Item 5</li>
    </ul>
</div>

Comments

-1

You could always set all of the elements to one variable:

var $lis = $('#header li, #footer li');
$($lis).css({color:"#ff0000"});

1 Comment

This is exactly what the OP said they didn't want to do.
-2

Use ES6 template literals for multiple variables as selectors:

$(`${$header_elements}, ${$footer_elements}`).css('color','#ff0000');

4 Comments

The variables are jQuery collections so you'll just get "[object Object], [object Object]"
In Gabriel's original question, they are neither arrays nor objects, but simple variables containing selectors. In that context, it works fine.
No they're not. var $header_elements = $("#header li"); var $footer_elements = $("#footer li"); <-- jQuery collections. And, you're missing the entire point of the question – "Is there a way to use my previously declared variables instead of a new selector?" and you're specifically creating a new selector.
If you want to answer an 8 years old question, please be sure that your answer is better than the accepted one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.