tags:

views:

83

answers:

5

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!

+5  A: 

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.

GenericTypeTea
Or to use his source examples: `$header_elements.add($footer_elements).css({color:'#ff0000'});`
gnarf
@gnarf updated.
GenericTypeTea
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!
Gabriel
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: http://jsbin.com/osupi3/2/edit
RussellUresti
+1  A: 

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
Raveren
+1  A: 

Pass an array of references:

$([$header_elements, $footer_elements]).css({color:"#ff0000"});
Anpher
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]])`
patrick dw
+2  A: 

I found the solutions a few minutes after posting this. For those who are wondering, here it is:

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

Is it faster? I don't know yet, I'll need to run some tests to find out.

EDIT:

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)
Gabriel
it will definitely be slower as jquery will have to merge the variables and then still go through them with `each`.
Raveren
Merge will append directly to `$header_elements` though... Making it contain `$footer_elements` as well
gnarf
See http://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 :)
gnarf
@Raveren - Take a look at the jsperf - The "slowerness" is almost un-noticeable.
gnarf
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: http://jsbin.com/osupi3/2/edit
RussellUresti
A: 

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

var $lis = $('#header li, #footer li');
$($lis).css({color:"#ff0000"});
Brian Ray
This is exactly what the OP said they **didn't** want to do.
GenericTypeTea