Frage Warum erlauben funktionale Pseudos wie: not () und: has () zitierte Argumente?


Offenbar, wie ich beim Kommentieren entdeckt habe eine andere Antwort, jQuery (eher die zugrunde liegende Selektor-Engine Brutzeln) können Sie das Argument an die zitieren :not() Selektor sowie die :has() Wähler. Nämlich:

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

In dem Selektoren StandardZitate sind immer repräsentativ für einen String und niemals für einen Selektor oder ein Schlüsselwort, also zitieren Sie das Argument :not() ist immer ungültig. Dies ändert sich nicht in den Selektoren 4.

Sie können auch sehen, dass es nicht standardmäßige Syntax ist, indem Sie ein hinzufügen nicht unterstützter CSS-Selektor sowie :nth-last-child(1)  wodurch der Selektor vollständig fehlschlägt:

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

Gibt es einen guten Grund, technische oder andere, um hier Zitate zuzulassen? Die einzigen Möglichkeiten, die Ihnen einfallen, sind:

  • Konsistenz mit :contains() Dies ermöglicht sowohl zitierte als auch nicht angeführte Argumente, wie in die alten Selektoren spec. Außer :contains() akzeptiert Strings / Keywords, keine Selektoren ...

  • Konsistenz mit der Implementierung von benutzerdefinierten Pseudos mit $.expr[':'], die immer zitierte und nicht angeführte Argumente erlaubt.

  • Konsistenz und Leichtigkeit der Portierung auf ihre Methoden Gegenstücke .not() und .has() (Entfernen oder trennen Sie die äußeren Anführungszeichen und ändern Sie die Doppelpunkte in Punkte?).

Aber ich kann keine Quellen finden, die sie unterstützen oder ihnen entgegenstehen. Tatsächlich ist die Fähigkeit, Selektorargumente selbst zu zitieren, nirgendwo dokumentiert, und es scheint auch keinen Unterschied zu geben, das Argument zu zitieren und nicht zu zitieren:

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

32
2017-09-18 10:56


Ursprung


Antworten:


Dies ist nicht spezifisch für :not(...) und :has(...) Selektoren - eigentlich alle Pseudos in Sizzle erlauben zitierte Argumente. Das Muster für pseudos Argumente ist definiert als:

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

Welche kann online gefunden werden 91 von sizzle.js ab 831c9c48...

Lassen Sie uns etwas Einrückung hinzufügen, um es lesbarer zu machen. Leider ist dies immer noch ein Regexp, also "ein bisschen besser lesbar" lässt viel zu wünschen übrig:

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

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

            "|" + // - OR -

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

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

Der Hauptgrund dafür ist: entweder einzelne oder doppelte Anführungszeichen um das Argument in einem Pseudo-Attribut verwendet. Backslash-Entkommen ist richtig behandelt, und so könnte jede beliebige Zeichenfolge als ein übergeben werden Streit. Beachten Sie, dass der "String" -Teil im selben Match-Index endet als der "Selektor" -Teil in dem obigen Regexp; Kurz gesagt, deshalb sie werden gleich behandelt: weil die pseudos Muster nicht Unterscheiden Sie zwischen den beiden. bearbeiten: ab jQuery 1.8.2, Argumente mit und ohne Anführungszeichen sind expliziter äquivalent. Ich kann nicht scheinen um diesen Code im jQuery-Git-Repository zu finden [Hilfe wäre willkommen], aber die Version von 1.8.2 gehostet von google, mit dem sha1sum von a0f48b6ad5322b35383ffcb6e2fa779b8a5fcffc, hat ein "PSEUDO": Funktion online 4206, die explizit a erkennt Unterschied zwischen "quoted" und "un quoted" Argumenten, und stellt sie sicher beide enden am selben Ort. Diese Logik tut es nicht unterscheiden zwischen der Art der Pseudo ("positional" oder nicht), die das Argument ist zum.

Da Sizzle Javascript-Strings verwendet, um den Auswahlprozess zu starten, Bei Argumenten wird nicht zwischen "String" und "Selektor" unterschieden werden an Funktionen übergeben. Diese Art der Unterscheidung wäre möglich, aber soweit ich weiß, ist immer was gewünscht leicht aus dem grundlegendsten Kontext (dh: welche Art von Pseudo wird benutzt), also gibt es keinen wirklichen Grund, das zu machen Unterscheidung. (Bitte korrigieren Sie die Kommentare, wenn sie nicht eindeutig sind Situationen, die mir nicht bewusst sind - ich würde es gerne wissen!).

Wenn also die Unterscheidung zwischen Strings und Selektoren nicht gegeben ist, bloße Implementierungsdetail, warum pseudos wie :eq(...) ausdrücklich solche Auswahlen ablehnen?

Die Antwort ist einfach: Es ist nicht wirklich. Zumindest nicht von jQuery 1.8.1. [bearbeiten: Ab jQuery 1.8.2 ist es überhaupt nicht. Die Argumente von "Positionale" Pseudos können genau wie alles andere zitiert werden. Das untere Hinweise zu den Implementierungsdetails von 1.8.1 bleiben als a historische Neugier]

Funktionen wie :eq(...) sind implementiert als:

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

Zu der Zeit, dass :eq(...) erhält das Argument, es ist immer noch in der Form eines bloßen Arguments (Anführungszeichen und alle). nicht wie :not(...), Dies Argument geht nicht durch a compile(...) Phase. Die "Ablehnung" von Das ungültige Argument ist tatsächlich auf das Shortcut-Casting via zurückzuführen +argument, was dazu führen wird NaN für jede in Anführungszeichen gesetzte Zeichenfolge (die in drehen, passt nie etwas). Dies ist noch eine weitere Implementierung Detail, obwohl in diesem Fall ein "richtig" sich verhält (wieder so weit wie ich weiß. Gibt es Situationen, in denen nicht-numerische Argumente zu solchen sind Funktionen sollten in der Tat übereinstimmen?)

bearbeiten: Ab jQuery 1.8.2 wurden die Dinge etwas überarbeitet, und "positional" -Pseudos erhalten das "rohe" Argument nicht länger. Als Ergebnis, zitierte Argumente werden jetzt in akzeptiert :eq(...) und dergleichen. Dieser Wandel scheint ein Nebeneffekt eines anderen Bugfixes zu sein, da die Unterstützung für in Anführungszeichen gesetzte Argumente im Changelog nicht erwähnt wird af8206ff .., die behoben werden sollte ein Fehler in der Handhabung :first und :last, jQuery-Fehler # 12303. Dieses Commit wurde mit verwendet git bisect und ein relativ einfaches Phantomjs-Skript. Es ist bemerkenswert, dass nach dem Sizzle in e89d06c4 ..Sizzle würde nicht nur für Selektoren wie :eq("3"), würde es tatsächlich eine Ausnahme werfen. Das sollte als weiterer Beweis dafür genommen werden :eq("3") Unterstützung ist kein beabsichtigtes Verhalten.

Es gibt in der Tat Gründe für benutzerdefinierte Filter, deren Argumente könnte in einigen Fällen als Strings und manchmal als gedacht werden Selektoren, egal wie sie oberflächlich aussehen, abhängig davon die Methode, in der sie ausgewertet werden ... aber so viel nähert sich das Pedantische. Es sollte genügen zu sagen, dass es keinen Unterschied gibt macht zumindest Dinge einfacher beim Aufruf von Funktionen, die, nein egal, was sie darstellen, erwarten Sie eine String-Darstellung.

Kurz gesagt, die ganze Situation kann als eine Implementierung betrachtet werden Detail, und ist in der Tatsache verwurzelt, dass Selektoren wie herumgereicht werden Strings an erster Stelle (wie sonst würden Sie sie in Sizzle bekommen?).


30
2017-09-19 22:47