Ich habe kürzlich Code in der Art von verwendet
$("#divMenuContainer:visible").hide("explode");
Nachdem ich einige Zeit damit verbracht hatte, es zum Laufen zu bringen, stellte ich fest, dass mein Selektor auf ein nicht vorhandenes Div verwies.
Das Ergebnis der Abfrage war einfach, dass sie nicht ausgeführt wurde.
Offensichtlich ist dies beabsichtigt. Kann jemand die Logik erklären, warum diese Designentscheidung getroffen wurde, anstatt eine Ausnahme zu machen?
Nicht versuchen zu kritisieren, sondern nur zu verstehen.
javascript
jquery
jquery-selectors
Maxim Gershkovich
quelle
quelle
Antworten:
Hier gibt es einige gute Gründe: "Verkettbarkeit" ist der Hauptantrieb. Die Fähigkeit, sehr knappen Code durch Verketten zu schreiben, muss keine Fehler verursachen, um scheinbar reibungslos zu funktionieren, zum Beispiel:
$("#divMenuContainer:visible").hide("explode").add("#another").fadeIn();
Jedes Objekt in der Kette, auch wenn es auf keine DOM-Elemente verweist, wurde möglicherweise später hinzugefügt, oder nehmen wir ein anderes Beispiel:
$("#divMenuContainer:visible").live("click", function() { ... });
In diesem Fall kümmern wir uns nicht um die Elemente, die der Selektor gefunden hat, sondern um den Selektor selbst. Hier ist ein anderes:
$("#divMenuContainer:visible").find(".child").hide("explode").end().fadeOut();
Selbst wenn es keine Kinder gibt, möchten wir möglicherweise später wieder in die Kette springen und weiterhin die
.prevObject
Referenz verwenden, um die Kette wieder hochzufahren.Es gibt Dutzende solcher Fälle, die zeigen, dass die Bibliothek so ist, wie sie ist. Wie für die warum , aus Interviews von John Resig , der der Schöpfer von jQuery ist, stellt er fest, dass das nur , wie es funktioniert. Er war nach Code so knapp wie möglich, und das Verkettungsmodell ist das, was aus dem Hut kam. Es hat zufällig auch viele Vorteile, das obige Beispiel sind nur einige davon.
Um es klar auszudrücken , ich sage nicht, dass jedes Attribut der Verkettung gut ist, es gibt nur viele Vorteile.
Nehmen wir diese Seite als Beispiel. Was wäre, wenn wir so etwas hätten:
$(".comment").click(replyToFunction);
Sollte das fehlschlagen, weil es noch keine Kommentare gibt? Nun, nein, nicht wirklich, das wird erwartet, ich würde hier keinen Fehler wollen ... wenn das Element existiert, mach es, wenn nicht. Mein Punkt ist, zumindest meiner Erfahrung nach, dass es enorm nützlicher ist , keinen Fehler wegen eines fehlenden Elements zu werfen, als einen zu werfen.
Der Selektor in Ihrer Frage, der
#ID
Selektor, ist ein ganz besonderer Fall, in dem Sie nur ein einziges Element erwarten. Vielleicht könnten Sie also argumentieren, dass es dort fehlschlagen sollte ... aber dann wäre das nicht mit anderen Selektoren vereinbar, und Sie möchten eine Bibliothek konsequent sein.Bei so ziemlich jedem anderen Selektor erwarten Sie 0-viele Elemente. Wenn Sie also keine Elemente finden, ist ein Fehlschlagen in den meisten Situationen erheblich weniger wünschenswert, insbesondere in den
.live()
oben genannten Fällen .quelle
if(!$("selector").length) { }
ist dies ein ziemlich kurzer Weg :) Sie können auch eine statische Methode für so etwas definieren..live()
wir uns nicht einmal um die darin enthaltenen DOM-Elemente kümmern ... es ist nicht so, dass die Liste null oder leer ist, wir kümmern uns nur nicht darum. Einige Dinge mit Verkettung verwenden es, andere nicht, manchmal verwenden sie andere Eigenschaften (.selector
und.context
in diesem Fall.prevObject
in anderen).jQuery.fn.require = function(num, num2) { if(this.length < num) $.error("At least " + num + " elements are required"); if(num2 && this.length > num2) $.error("Between " + num + " and " + num2 + " elements required"); };
Sie können es hier testen / spielen: jsfiddle.net/nick_craver/VrXmc Überprüfen Sie die Konsole auf Fehler.Betrachten Sie es als eine Abfrage , die es ist. Sie fragen nach allen "Datensätzen" (DOM-Elementen), die Ihren Kriterien entsprechen. Das Ergebnis ist ein Satz von Nulldatensätzen.
Anschließend werden Ihre Null-Datensätze durchlaufen und die Aktion auf sie angewendet. :) :)
Wenn Sie dasselbe mit SQL oder einem Array tun, verhält es sich in den meisten Sprachen genauso. Eine Sammlung von Nulldatensätzen ist kein Fehlerzustand.
var things = $("invalid selector"); $("p").text("The object is valid: " + things + " but has " + things.length + " elements.")
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <p></p>
quelle
Es ist eine Frage der Flexibilität. Ich selbst möchte den gleichen Schutz, den Sie verlangen, Sie können es immer selbst tun. Verwenden:
jQuery.fn.single = function() { if (this.length != 1) { throw new Error("Expected 1 matching element, found " + this.length); } return this; };
und verwenden Sie jetzt $ ("input: checked"). single () mit der Gewissheit, dass entweder ein einzelnes Element zurückgegeben wird oder Sie einen Fehler erhalten.
quelle
jQuery () gibt immer ein jQuery-Objekt zurück, um Fehler zu vermeiden, aber was noch wichtiger ist:
So können Sie reaktionsschnellen Code schreiben.
do X if Y is present
Wenn Y nicht vorhanden ist, berechnet X nicht.
Dies bedeutet, dass Sie globale Init-Cross-Pages haben können und nur Init-Plugins, ob sie etwas finden oder nicht.
$(function(){ // does nothing if the page contains no element with className 'accordion' $('.accordion').implementAccordion(); // usually on a single page, but we can add it to a global js file nontheless. $('.validate-form').implementFormValidator(); });
Natürlich sind einige Plugins wirklich schlecht geschrieben und werfen einen Fehler auf.
quelle
Es ist Teil der Philosophie von jQuerys (eigentlich John Resigs, denke ich) über die Bibliothek.
Es versucht, "freundlich" zu Ihnen und Ihren Kunden zu sein, was wiederum bedeutet, dass es ziemlich selten Ausnahmen gibt
(wie wirklich selten).
Aber wie immer können Sie es einfach erweitern wie:
(function(_jQuery){ jQuery = function(){ var ret = _jQuery.apply(this, arguments); if(!ret.length) throw new Error('empty selector'); return ret; }; }(jQuery));
Aber wie
Nick
in einem Kommentar gesagt, ist dies meistens kein gewünschtes Verhalten. Wenn Sie es trotzdem aus irgendeinem Grund haben möchten, sollte es ein Code-Snippet wie das oben genannte tun.quelle
Ein Selektor, der sich nicht auf Elemente bezieht, ist immer noch ein legaler Selektor und kann beabsichtigt sein. Es kann sein, dass ein bestimmter Selektor manchmal Elemente zurückgibt, und Sie möchten einen solchen Selektor verwenden können, ohne die Möglichkeit zu haben, Laufzeitfehler auszulösen.
quelle
Ein gutes Beispiel ist, wenn Sie mit allen aktivierten Kontrollkästchen etwas unternehmen möchten
$("input:checked")
... Sie wissen nicht, wie viele überprüft werden. Könnte jeder sein, alle oder keine. Das hängt vom Benutzer ab.
Also, anstatt Code wie schreiben zu müssen
var checkedInputs = $("input:checked"); if (checkedInputs && checkedInputs .length > 0) { checkedInputs .doStuff(); }
Sie können einfach
$("input:checked").doStuff();
Und wenn sie eine Auswahl getroffen haben, großartig, wird alles erledigt. Wenn nicht ... kein Schaden, kein Foul.
quelle
if()
Erklärung wird immer bewertettrue
, sodass Sie einfach Folgendes tun können :if(checkedInputs.length > 0) {...
. Oder da eine beliebige Zahl größer als0
gleich isttrue
, können Sie sie auf reduzierenif(checkedInputs.length) {...
. : o)da
$("#thisdivdoesntexist")
in jQuery immer noch eine 'leere' jQuery zurückgegeben wirdObject
und alle jQuery-Objekte ihre Methoden haben, also kein Fehler.Das ist eigentlich eine gute Sache. Wenn dies einen Fehler auslösen würde, müssten Sie in vielen Fällen einige zusätzliche Überprüfungen durchführen, bevor Sie etwas tun, was bedeutet, dass Sie viel Überlastungscode haben würden. Obwohl es keine schlechte Praxis wäre, vor dem Aufrufen einer Methode für das Objekt zu überprüfen, ob sie vorhanden ist, wird nicht alles Javascript angehalten, wenn der Selektor nichts zurückgibt (was passieren würde, wenn es einen Fehler auslösen würde).
Daher können Sie Selektoren global verwenden, auch wenn einige Seiten nicht über den Selektor verfügen, ohne sich darüber wirklich Gedanken machen zu müssen.
quelle
$('something')
immer ein jQuery-Objekt zurück. Im Fall von$("#thisdivdoesntexist")
hat das Objekt 0 Elemente.jQuerys constructor function
, aber dies sollte wahrscheinlich zumindest eine Warnung auslösen .Normalerweise fahre ich nur fort, wenn die Elemente existieren, indem ich etwas in der Art von:
var aThing = $("#myElement"); if(aThing.length){ //my code here }
quelle
Ich denke, dass es wahrscheinlich damit zu tun hat, dass Ihr Selektor:
$("#divMenuContainer:visible")
Unter dem Deckblatt wird ein jQuery-Objekt zurückgegeben, das eine Reihe möglicher Übereinstimmungen enthält. Die Funktion Ausblenden wird dann für jede dieser Funktionen ausgeführt. Ich stelle mir vor, dass es in diesem Fall keinen Sinn macht, keine Ausnahme auszulösen, da Sie eine Liste mit null Einträgen haben, anstatt eine Null zurückzubekommen.
quelle
Für mich macht es nur Sinn ... Wenn Ihr Selektor keinem Element entspricht, können Sie trotzdem alle normalen jQuery-Prototypfunktionen aufrufen, ohne Fehler zu generieren! Im schlimmsten Fall erhalten Sie ein 'leeres' jQuery-Set, das Ihre Änderungen auf keine Elemente anwendet.
quelle
Ich denke, weil es im Front-End verwendet wird - Endbenutzer sollten keine Ausnahmen sehen, weil ein Entwickler einen schlechten Code geschrieben hat. In diesem Fall ist es wahrscheinlich im Allgemeinen sicherer, stillschweigend zu versagen.
quelle
Ich dachte, es sollte wie CSS sein. Wenn Sie also versuchen, ein Element zu formatieren, das nicht vorhanden ist, erhalten Sie keinen Fehler.
quelle