17

let's say that I have some

<TR style = "background-color : red ;">

and some

<TR>

(to be noted that the spaces next to the colon and to the semicolon are intentional, because the page I am dealing with is written in that way)

now, this:

$('.detailtable tr:not([style~="darkgray"])')

works perfectly. But here it says:

[name!="value"] cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. For better performance in modern browsers, use $("your-pure-css-selector").not('[name="value"]') instead

so I was wondering: is my expression the best one or something like:

$('.detailtable tr').not('[style~="darkgray"]') // this doesn't work!

is better performing? And what is the correct way of writing this last expression?

Thanks in advance

Pierpaolo
  • 567
  • 3
  • 7
  • 17
  • `$('.detailtable tr').not('[style~="darkgray"]') ` should work the same. If you are worried about performance, test it: http://jsperf.com/. – Felix Kling Jun 13 '12 at 14:51
  • as I wrote in the comment, $('.detailtable tr').not('[style~="darkgray"]') doesn't work... – Pierpaolo Jun 14 '12 at 07:29

3 Answers3

35

If you really want to "select element that does not contain a string within an attribute", you should use *= instead of ~=, like so:

$('.detailtable tr').not('[style*="darkgray"]');

Here's the fiddle.


And no, using .not is probably not faster. querySelectorAll should be able to parse that selector as is.

See this fiddle.


Edit: If you care about IE8 that much, then using the .not method instead of the :not selector will give you a small performance boost. The reason for this is very simple: IE8 does support attribute selectors, but not the negation selector.

Stacked
  • 6,892
  • 7
  • 57
  • 73
Joseph Silber
  • 214,931
  • 59
  • 362
  • 292
  • Yes, it'll work with `querySelectorAll()` because it's a valid CSS selector. See also: [What is the difference in the :not() selector between jQuery and CSS?](http://stackoverflow.com/questions/10711730/whats-the-difference-in-the-not-selector-between-jquery-and-css) (I was going to write a small section about how people should stop caring about performance, but I figured people out there probably already care too much about performance to care to read that, so I didn't care to write it...) – BoltClock Jun 13 '12 at 14:58
  • @BoltClock - of course there are differences between the native `:not` selector and jQuery's beefed up `:not`. However, in this case, it's safe to assume that the native implementation will handle it just fine. – Joseph Silber Jun 13 '12 at 15:00
  • @BoltClock - I care very much about performance, but I would gladly hear your opinion. Care to share? I'd read it even if it were small-novel-book length... – Joseph Silber Jun 13 '12 at 15:02
  • Well, I tend to only worry about performance if performance is critical. I don't try to optimize or agonize over every single line of code until and unless a bottleneck is found. That said it's always good practice to write selectors that can take advantage of `querySelectorAll()` as much as possible, but deliberately making things overly complicated just to save milliseconds is going overboard in my book... – BoltClock Jun 13 '12 at 15:05
  • @BoltClock - Thanks for sharing your thoughts, and I wholeheartedly agree. Legibility definitely comes before a minor speed boost. However, in this case, I think using `.not` is even more legible (read: scan-able), since it's not just one single long string. – Joseph Silber Jun 13 '12 at 15:08
  • @JosephSilber: thanks, but now I'm curious: what's the difference between `~=` and `*=`? From jQuery documentation: `[name~="value"] Selects elements that have the specified attribute with a value containing a given word, delimited by spaces. [name*="value"] Selects elements that have the specified attribute with a value containing the given substring.` so? `~=` does an exact match while `*=` does not? – Pierpaolo Jun 14 '12 at 07:37
  • 1
    @Pierpaolo - given the following element: ``, using `[class~=two]` will match, whereas with `` it won't match. `[name*=two]` will match in both cases. – Joseph Silber Jun 14 '12 at 13:45
  • @JosephSilber OK, precisely as I've guessed, then. Thanks *Edit*: as I said in the question text: it does not work! – Pierpaolo Jun 14 '12 at 14:44
  • **Second attempt:** although it works with jQuery 1.7.2, with version 1.6.4 (the version I am currently using) doesn't work – Pierpaolo Jun 14 '12 at 14:52
0

I'd suggest you take a look at this.

Interestingly enough, pseudo selectors (like ":not") tend to actually be slower than using a function next to the initial selector. In fact... they're apparently "twice as slow".

I quote:

  1. $("#id p");
  2. $("#id").find("p");

Would it surprise you to learn that the second way can be more than twice as fast as the first? Knowing which selectors outperform others (and why) is a pretty key building block in making sure your code runs well and doesn’t frustrate your users waiting for things to happen.

I'd go with .not my friend!

cereallarceny
  • 4,913
  • 4
  • 39
  • 74
  • According to http://jsperf.com/id-vs-class-vs-tag-selectors/2, pseudo-selectors are the slowest of all selectors. I haven't found any evidence that says they are faster than chaining a jQuery function afterwards. Then again, just because I haven't found said evidence doesn't mean it doesn't exist. :) – cereallarceny Jun 13 '12 at 15:29
0

From the W3C Recommendation, what you currently use should work perfectly fine even with document.querySelectorAll().

Maybe you can test if it works as expected.

Stacked
  • 6,892
  • 7
  • 57
  • 73
Sujay
  • 2,198
  • 23
  • 32
  • `:not()` was added to the draft many years ago, and jQuery picked up on it soon enough... – BoltClock Jun 13 '12 at 14:57
  • @BoltClock But the [selectors table](http://www.w3.org/TR/css3-selectors/#selectors) mentions `3` in `First defined in CSS level` column for the Negation Pseudo Class. Hence I thought this was a recent addition to the selectors list. Please provide any references to confirm that this was picked up by jQuery earlier. I'll wait for you response before editing. – Sujay Jun 13 '12 at 15:03
  • CSS3 was only made a recommendation recently, but it was in draft for more than 10 years and `:not()` has been around for just as long (go to the spec page and keep clicking on "Previous version"). jQuery shipped with `:not()` in its first major stable release - it says "version added: 1.0" in the [docs](http://api.jquery.com/not-selector). – BoltClock Jun 13 '12 at 15:07