Can I force jQuery to use Sizzle to evaluate a selector without using non-standard selectors?
Asked Answered
V

3

7

In modern browsers, jQuery makes use of document.querySelectorAll() to boost performance when valid CSS selectors are used. It falls back to Sizzle if a browser doesn't support the selector or the document.querySelectorAll() method.

However, I'd like to always use Sizzle instead of the native implementation when debugging a custom selector. Namely, I'm trying to come up with an implementation of :nth-last-child(), one of the CSS3 selectors that are not supported by jQuery. Since this selector is natively supported by modern browsers, it works as described in the linked question. It is precisely this behavior that's interfering with debugging my custom selector, though, so I'd like to avoid it.

A cheap hack I can use is to drop in a non-standard jQuery selector extension, thereby "invalidating" the selector so to speak. For example, assuming every li:nth-last-child(2) is visible, I can simply drop that in, turning this:

$('li:nth-last-child(2)').css('color', 'red');

Into this:

$('li:nth-last-child(2):visible').css('color', 'red');

This causes it to always be evaluated by Sizzle. Except, this requires that I make an assumption of my page elements which may or may not be true. And I really don't like that. Not to mention, I dislike using non-standard selectors in general unless absolutely necessary.

Is there a way to skip the native document.querySelectorAll() method in browsers that support it and force jQuery to use Sizzle to evaluate a selector instead, that preferably doesn't employ the use of non-standard selectors? Likely, this entails calling another method instead of $(), but it's much better than a selector hack IMO.

Veracruz answered 31/7, 2012 at 20:8 Comment(3)
If it's for debugging you could try overwriting or deleting the document.querySelectorAll() function perhaps.Rally
+1 for attempting this. Awesome :)Predestine
I didn't try it: github.com/cowboy/jquery-misc/blob/master/…Mazman
A
9

You could just set it to null before jQuery loads so it thinks it's not supported:

document.querySelectorAll = null;
//load jquery, will trigger not supported branch
//Optionally restore QSA here (save a reference) if needed

This is supposed to make this evaluate to false

Demo: http://jsbin.com/asipil/2/edit

Comment out the null line and rerun, and you will see it will turn red.

Arnaud answered 31/7, 2012 at 20:11 Comment(4)
Yet another case of something being so obvious that somebody else has to point it out to me. Can't believe I missed it :) I forgot to mention that I'd prefer to leave the native implementation alone as well, but if there isn't any other solution, then I guess this will have to do.Veracruz
Does it work? Do browsers allow to override this property and if yes, all of them? edit: Seems to work in Chrome at least.Guria
I don't believe you have to do this, see my answer.Snigger
+1 @Arnaud looks like in 1.9 it is working ...:-) jsbin.com/asipil/11/editSunnysunproof
P
3

Since you're developing the code for the selector yourself, could you not simply give it a custom name for the duration of the development cycle? Maybe give it your own vendor prefix or something? -bolt-nth-last-child()

That way, you'll know the browser definitely won't support it, so it should always fall into using Sizzle.

When you're done with the development cycle, you can drop the -bolt- prefix.

I know that's more of a work-around than an answer to the question, but it seems like the simplest solution to me.

Predestine answered 31/7, 2012 at 20:59 Comment(0)
S
0

It looks to be that jQuery.find defaults to sizzle. This will save you from destroying your environment by setting a native function to null.

https://github.com/jquery/jquery/blob/master/src/sizzle-jquery.js#L3

So you should be able to do the following and it will always go through sizzle.

$.find('li:nth-last-child(2)')
Snigger answered 31/7, 2012 at 20:14 Comment(4)
If the document.querySelectorAll test evaluates to true then Sizzle has been overwritten before this assignment. See view-source:code.jquery.com/jquery-1.7.2.js line 5093Arnaud
The Sizzle method that is referenced in that line contains the native calls before falling back to its internal implementation (I'm guessing this is the overwritten implementation @Arnaud is referring to). Start here. I made a fiddle and indeed, it shows :nth-last-child() working so it's still using the native method.Veracruz
Can you point to where exactly it's making the distinction? The only reference to querySelectorAll is from 1316 down, and I don't see anything that tells it to use querySelectorAll if an assert fails. github.com/jquery/sizzle/blob/master/sizzle.js#L1316Snigger
@Snigger in the case of that github file select is same as Sizzle in jQuery file. You can now see that if the document.querySelectorAll test evaluates to true, select (I.E. Sizzle in jQuery), will get overwritten with the version that uses native query selector. See here: github.com/jquery/sizzle/blob/master/sizzle.js#L1370Arnaud

© 2022 - 2024 — McMap. All rights reserved.