2012-09-18 16 views
32

Aparentemente, como he descubierto al comentar en another answer, jQuery (más bien su motor de selector subyacente Sizzle) le permite citar el argumento al selector :not(), así como al selector :has(). To wit:¿Por qué los pseudos funcionales tales como: not() y: has() permiten argumentos entrecomillados?

$('div:not("span")') 
$('span:has("span")') 

En el Selectors standard, citas siempre son representativas de una cadena y nunca de un selector o una palabra clave, por lo que el argumento citando a :not() es siempre válido. This will not change in Selectors 4.

También puede ver que es la sintaxis no estándar mediante la adición de un unsupported CSS selector como :nth-last-child(1)causing the selector to fail completely:

$('div:not("span"):nth-last-child(1)') 
$('span:has("span"):nth-last-child(1)') 

¿Hay alguna buena razón, técnica o de otra manera, por permitir que las cotizaciones aquí? Las únicas posibilidades que vienen a la mente son:

  • Coherencia con :contains() que permite argumentos tanto cotizadas y no cotizadas, como se ve en the old Selectors spec. Excepto :contains() acepta cadenas/palabras clave, no los selectores ...

  • compatibilidad con la ejecución de pseudos personalizados utilizando $.expr[':'], que siempre permite citado y los argumentos no cotizados.

  • consistencia y facilidad de portar a sus homólogos método .not() y .has() (acaba de quitar o dividir las cotizaciones externas y cambiar colones por períodos?).

Pero no puedo encontrar ninguna fuente que los apoye o se oponga a ellos. De hecho, la capacidad de citar selector sí argumentos no está documentada en cualquier lugar, ya sea, ni tampoco parece haber ninguna diferencia entre cotización y no citando el argumento:

$('div:not(span)') 
$('span:has(span)') 
+5

Esto es probablemente una peculiaridad de [Sizzle] (http://sizzlejs.com/), no de jQuery. – lanzz

+1

@BoltClock Lo siento, mi ejemplo fue malo, creo que el único propósito de las citas es escapar. – undefined

+0

Probablemente sea por coherencia en la implementación de '$ .expr [':']'. – zzzzBov

Respuesta

30

Esto no es específico de :not(...) y :has(...) selectores - en realidad, todos los pseudos en Sizzle permiten argumentos entrecomillados. El patrón de argumentos pseudos' se define como:

pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)" 

que se pueden encontrar en la línea 91 of sizzle.js as of 831c9c48...

Vamos a añadir un poco de sangrado para que, para que sea un poco más fácil de leer. Desafortunadamente, esto sigue siendo una expresión regular, por lo que "un poco más legible" aún deja mucho que desear:

pseudos = (
    ":(" + characterEncoding + ")" + 
    "(?:" + 
    "\\(" + // literal open-paren 
     "(?:" + 

       "(['\"])" + // literal open-quote 
        "((?:\\\\.|[^\\\\])*?)" + // handle backslash escaping 
       "\\2" + // close-quote 

      "|" + // - OR - 

       "(" + 
        "[^()[\\]]*" + 
        "|" + 
        "(?:" + 
         "(?:" + attributes + ")" + 
         "|" + 
         "[^:]" + 
         "|" + 
         "\\\\." + 
        ")*" + 
        "|" + 
        ".*" + 
       ")" + 

     ")" + 
    "\\)" + // literal close-paren 
    "|" + // ie, 'or nothing' 
")" 
); 

La principal para llevar de esto es: ya sea sola o comillas dobles pueden ser usado alrededor del argumento en un pseudo-atributo. El escape de barra invertida es correctamente manejado, por lo que cualquier cadena arbitraria podría pasarse como un argumento .Tenga en cuenta que la parte "string" termina en el mismo índice de coincidencia como la parte "selector" en la expresión regular anterior; por lo tanto, en resumen, es por eso que se tratan por igual: porque el patrón pseudos no distingue entre los dos. editar: a partir de jQuery 1.8.2, los argumentos con y sin comillas son más explícitamente equivalentes. Parece que no puedo encontrar este código en el GIT jQuery repositorio [ayuda se agradece], pero the version of 1.8.2 hosted by google, having the sha1sum of a0f48b6ad5322b35383ffcb6e2fa779b8a5fcffc, tiene una función "PSEUDO": en la línea 4206, lo que detecta de forma explícita una diferencia entre los argumentos "no cotizados", "citado" yy asegura que terminen en el mismo lugar. Esta lógica hace no distinguir entre el tipo de pseudo ("posicional" o no) para el cual el argumento es .

Como Sizzle utiliza cadenas de Javascript para iniciar el proceso de selección, no hay distinción entre "cadena" y "selector" cuando los argumentos se pasan a las funciones. Hacer ese tipo de distinción sería posible, pero hasta donde yo sé, lo que realmente se desea siempre es fácilmente determinado desde el contexto más básico (es decir: qué tipo de pseudo se está utilizando ), por lo que no hay razón real para hacer la distinción . (corrija en los comentarios si hay situaciones ambiguas de las que no estoy consciente; me gustaría saber).

Así pues, si la falta de distinción entre las cuerdas y selectores es un mero detalle de implementación , ¿por qué los pseudos como :eq(...) explícitamente rechazar estos procesos de selección?

La respuesta es simple: no lo es, de verdad. Al menos, no a partir de jQuery 1.8.1. [editar: a partir de jQuery 1.8.2, no lo hace en absoluto. Los argumentos de pseudos "posicionales" pueden citarse como cualquier otra cosa. Los siguientes notas con respecto a los detalles de implementación de 1.8.1 se dejan como una curiosidad histórica ]

Funciones tales como :eq(...) se implementan como:

"eq": function(elements, argument, not) { 
    var elem = elements.splice(+argument, 1); 
    return not ? elements : elem; 
} 

En el momento en que recibe :eq(...) el argumento, es todavía en la forma de un argumento simple (comillas y todo). A diferencia de :not(...), este argumento no pasa por una fase compile(...). El "rechazo" de el argumento inválido es en realidad debido al acceso directo a través del +argument, que dará como resultado NaN para cualquier cadena entrecomillada (que en giro, nunca coincide con nada). Este es otro detalle de implementación , aunque en este caso una "correcta" comportarse uno (de nuevo, en la medida que yo sepa. ¿Hay situaciones en las que los argumentos no numéricos a dichos funciones deberían juego está hecho?)

editar: A partir de jQuery 1.8.2, las cosas se han refactorado un poco, y pseudos "posicionales" ya no reciben el argumento "sin formato". Como resultado, ahora se aceptan los argumentos citados en en :eq(...) y similares.Este cambio parece haber sido un efecto secundario de otra corrección de errores, ya que no hay mención de soporte para argumentos cotizados en el registro de cambios para af8206ff.., que se diseñó para reparar an error in handling :first and :last, jQuery bug #12303. Esta confirmación se encontró usando git bisect y a relatively simple phantomjs script. Es notable que después de la reescritura de Sizzle en e89d06c4.., Sizzle no solo fallaría silenciosamente para selectores como :eq("3"), en realidad arrojaría una excepción. Eso debe tomarse como una evidencia más de que el soporte :eq("3") no es el comportamiento previsto.

De hecho, existen razones relativas a los filtros personalizados, cuyos argumentos podría en algunos casos ser considerados como cadenas, y en ocasiones como selectores, no importa lo que superficialmente se parecen, en función de el método en el que se evalúan. .. pero eso se acerca al pedante. Debería bastar con decir que no tener una distinción al menos simplifica las cosas al llamar funciones que, sin importar lo que representen, , esperan una representación de cadena.

En resumen, la situación puede ser pensado como una implementación detalle, y tiene su origen en el hecho de que los selectores se pasan alrededor como cadenas en el primer lugar (¿cómo podrías ellos entrar en Arden?).

+0

¿No has oído hablar de [raw cadenas] (http://docs.python.org/reference/lexical_analysis.html#string-literals)? O tal vez somos solo yo y Python ... –

+1

+1 por tomarse el tiempo para formatear la expresión regular e intentar explicarla (lo cual es una tarea formidable). La recompensa es suya por tomar. –

+0

Creo que en realidad necesito pasar por todo de nuevo.Su comentario me impulsó a darle otra mirada, y creo que puedo haber leído mal, a pesar de todos mis esfuerzos de formateo. Tampoco he avanzado en el proceso de tokenización desde que se lanzó jQuery 1.8.2, así que realmente debería asegurarme de que el razonamiento sigue siendo preciso. –

Cuestiones relacionadas