getElementsByClassName als Methode von document?
Felix Riesterer
- javascript
0 Struppi0 molily0 derletztekick1 Mathias Brodala
Liebe JS-Könner,
ich brauche manchmal die Funktion document.getElementsByClassName(), die jedoch nicht im bisherigen Javascript-Sprachumfang implementiert ist.
Ich habe mir einfach eine solche Funktion geschrieben:
function getElementsByClassName(className) {
var muster = new RegExp("(^| )" + className + "($| )");
var alles = document.getElementsByTagName("*");
var gefunden = new Array();
var i;
for (i=0; i < alles.length; i++) {
if (alles[i] && alles[i].className && alles[i].className != "") {
if (alles[i].className.match(muster))
gefunden[gefunden.length] = alles[i];
}
}
return gefunden;
}
Nun möchte ich diese Funktion als Methode des document-Objektes haben. Wie bekomme ich jetzt meine Funktion dazu, dass sie sich auf das document bezieht? Einfach ein document.getElementsByClassName = function (className) {...}
reicht ja nicht, da in meinem Funktionscode das document-Objekt fest benutzt wird. Durch die Schreibweise "document.getElementsByClassName" soll aber genau dieser Zusammenghang klar werden, ohne dass ich in meinem Code "document.xyz" notieren muss.
Wie geht das? Brauche ich etwas wie "prototype"?
Liebe Grüße aus Ellwangen,
Felix Riesterer.
if (alles[i] && alles[i].className && alles[i].className != "") {
Der letzte Vergleich dürfte überflüssig sein
Nun möchte ich diese Funktion als Methode des document-Objektes haben. Wie bekomme ich jetzt meine Funktion dazu, dass sie sich auf das document bezieht? Einfach ein
document.getElementsByClassName = function (className) {...}
reicht ja nicht, da in meinem Funktionscode das document-Objekt fest benutzt wird. Durch die Schreibweise "document.getElementsByClassName" soll aber genau dieser Zusammenghang klar werden, ohne dass ich in meinem Code "document.xyz" notieren muss.
Das verstehe ich nicht, document.xyz ist der einzige Weg, den alle Browser verstehen.
Struppi.
Lieber Struppi,
erst einmal danke für Deine Antwort!
Das verstehe ich nicht, document.xyz ist der einzige Weg, den alle Browser verstehen.
Ich meinte das so, dass ich innerhalb meiner Funktion im Code das document-Objekt nicht erneut notieren muss, da der Bezug zu eben diesem Objekt ja schon durch den Funktionsaufruf document.xyz() klar ist. Irgendwie könnte das mit dem Schlüsselwort "this" geschehen, nur habe ich keine Ahnung, wie.
Beispiel:
document.getElementsByTagName("a") // Holt alle Anker aus document
document.forms[0].getElementsByTagName("a") // Holt alle Anker aus dem ersten Formular (sonst keine!)
Im obigen Beispiel ist der zweite Funktionsaufruf auf das erste Formular im Dokument beschränkt. Die Funktion "getElementsByTagName" bezieht sich hier nur auf das Formular-Objekt, nicht jedoch auf das ganze Dokument (vergleiche ersten Aufruf). Wie kann ich diesen Umstand im meiner Funktion von der Schreibweise her nachbilden?
Ich glaube, ich brauche da etwas wie Konstruktor oder prototype, nur verstehe ich davon noch viel zu wenig. Daher meine Frage...
Liebe Grüße aus Ellwangen,
Felix Riesterer.
Hallo,
Durch die Schreibweise "document.getElementsByClassName" soll aber genau dieser Zusammenghang klar werden, ohne dass ich in meinem Code "document.xyz" notieren muss.
this.getElementsByTagName
this in einer Funktion verweist auf das Objekt, dessen Methode die Funktion ist (oder window, wenn die Funktion eine lokale Variable ist).
document.func = function () {
alert(this === document);
};
document.func();
Voraussetzung ist die Aufrufweise »objekt.methode()«.
Mathias
Lieber Mathias,
vielen Dank für Deinen Hinweis!
this in einer Funktion verweist auf das Objekt, dessen Methode die Funktion ist (oder window, wenn die Funktion eine lokale Variable ist).
document.func = function () {
alert(this === document);
};
document.func();
Damit kann ich nun tatsächlich "document.getElementsByClassName" verwenden. SUPER!
Wie kann ich das ausweiten auf alle HTML-Elemente? Es wäre chic, wenn ich diese Funktion auf ein beliebiges HTML-Element anwenden könnte, um nur dessen Kindknoten zu erhalten, anstatt alle Knoten des gesamten Dokuments.
Braucht es dazu prototype? Und wenn ja, wie definiere ich das so, dass es sich auf alle HTML-Objekte bezieht? Ich habe im Archiv gelesen, dass man streng zwischen Javascript und DOM trennen muss, und genau hier scheint sich diese Grenze aufzutun...
Liebe Grüße aus Ellwangen,
Felix Riesterer.
Hallo Felix Riesterer,
Wie geht das? Brauche ich etwas wie "prototype"?
Hmm, scheint so. Auf anhieb schien das zu funktionieren:
Object.prototype.getElementsByClassName = function(className){
var muster = new RegExp("(^| )" + className + "($| )");
var alles = document.getElementsByTagName("*");
var gefunden = new Array();
var i;
for (i=0; i < alles.length; i++)
if (alles[i] && alles[i].className && alles[i].className != "")
if (alles[i].className.match(muster))
gefunden[gefunden.length] = alles[i];
return gefunden;
}
Wobei nun wahrscheinlich jedes Object diese Methode hat; es geht vermutlich besser...
Mit freundlichem Gruß
Micha
Hallo,
Wie geht das? Brauche ich etwas wie "prototype"?
Hmm, scheint so.
Kommt drauf an, was Felix will...
Object.prototype.getElementsByClassName
Wenn schon, dann HTMLElement.prototype, was aber IE bekanntlich auch nicht kann.
Object.prototype zu erweitern ist nicht ohne und hat weitreichende Konsequenzen, daraufhin muss man jede for-in-Schleife mit einer hasOwnProperty-Abfrage versehen. Also lieber Finger weg davon, wenns auch anders geht.
var alles = document.getElementsByTagName("*");
Dann hier natürlich this, wie gesagt.
Mathias
Lieber Mathias,
Wenn schon, dann HTMLElement.prototype, was aber IE bekanntlich auch nicht kann.
Aha! Also in nicht-IEs wäre das eine Option? Und wie macht man dann den IE gefügig?
Liebe Grüße aus Ellwangen,
Felix Riesterer.
hi,
Wenn schon, dann HTMLElement.prototype, was aber IE bekanntlich auch nicht kann.
Aha! Also in nicht-IEs wäre das eine Option? Und wie macht man dann den IE gefügig?
Wenn's ein wenig von hinten durch die Brust ins Auge sein darf - dann vielleicht analog dazu, wie es Jason Karl Davis in DOM2 EventTarget in IE zeigt:
Die Funktionalität wird in einem HTC untergebracht, und dann per Universal-Selektor * und behaviour im CSS an alle Elemente "drangehängt".
(An document muss sie nach wie vor mit dem im Thread schon genannten Weg angehängt werden, denn document wird ja nicht durch CSS selektiert.)
Ich habe allerdings keine Ahnung, wie performant das ist - und schwanke auch noch innerlich, ob ich diesen Ansatz eher als clever, oder als total meschugge ansehen soll :-)
gruß,
wahsaga
Lieber wahsaga,
Die Funktionalität wird in einem HTC untergebracht
[...]
ob ich diesen Ansatz eher als clever, oder als total meschugge ansehen soll :-)
danke Dir für diesen Hinweis. Das ist wirklich sehr verzwickt. :-)
Ich bleibe lieber bei meiner ursprünglichen Version von meiner Funktion, der ich eben einen optionalen zweiten Parameter mitgebe, der dann das aktuelle HTML-Element referenziert, innerhalb dessen ich die Nachfahrenknoten ermitteln lasse.
window.getElementsByClassName = function (className, element) {
var muster = new RegExp("(^| )" + className + "($| )");
var alles = element.getElementsByTagName("*");
var gefunden = new Array();
var i;
element = element ? element : document;
for (i=0; i < alles.length; i++) {
if (alles[i] && alles[i].className && alles[i].className != "") {
if (alles[i].className.match(muster))
gefunden[gefunden.length] = alles[i];
}
}
return gefunden;
}
In dieser Art wurde eine solche Funktion ja im Forum schon öfter diskutiert - anscheinend geht es browser(krücken)übergreifend nicht besser...
Liebe Grüße aus Ellwangen,
Felix Riesterer.
hallo again Felix,
Ich bleibe lieber bei meiner ursprünglichen Version von meiner Funktion,
der ich eben einen optionalen zweiten Parameter mitgebe, der dann das
aktuelle HTML-Element referenziert, innerhalb dessen ich die Nachfahrenknoten
ermitteln lasse.
eben, das ist durchaus der ansatz fuer schlankeren und uebersichlicheren code;
und fuer den fall dieser einen methode sowiso.
window.getElementsByClassName = function (className, element) {
var muster = new RegExp("(^| )" + className + "($| )");
var alles = element.getElementsByTagName("*");
var gefunden = new Array();
var i;element = element ? element : document;
>
> ...
hier muesstest Du die letzte pruefung aber ganz nach oben ziehen und etwas
strikter pruefen, damit man Dir keinen mist unterjubeln kann; und auf das
leerzeichen als einzigen \*whitespace\* wuerde ich mich an Deiner stelle auch
nicht verlassen wollen.
~~~javascript
window.getElementsByClassName = function (className, element) {
var gefunden = [];
//if ((typeof className == "string") || (className instanceof String)) {
if (className) { // fliegt raus bei: [undefined], [null], [false], 0, "".
//element = ((element && ((typeof element.getElementsByTagName == "function") || ((typeof element.getElementsByTagName == "object") && !obj))) ? (element) : (document));
element = ((element && element.getElementsByTagName) ? (element) : (document));
var muster = new RegExp("(^|\\s+)" + String(className) + "($|\\s+)"); // typecast wenn nur ueber >>if (className) {<< geprueft
var alles = element.getElementsByTagName("*");
var i;
...
so long - peterS. - pseliger@gmx.net
Hallo,
Ich bleibe lieber bei meiner ursprünglichen Version von meiner Funktion,
der ich eben einen optionalen zweiten Parameter mitgebe, der dann das
aktuelle HTML-Element referenziert, innerhalb dessen ich die Nachfahrenknoten
ermitteln lasse.eben, das ist durchaus der ansatz fuer schlankeren
Nö; Die Prototype-Variante ist - abgesehen von den IE-Würgarounds (die man am Besten in externe Dateien auslagert und per CCs nur dem IE zugänglich macht) - auch nicht viel umfangreicher:
HTMLElement.prototype.getElementsByClassName = function(klasse){
var alles = this.getElementsByTagName("*");
…
}
uebersichlicheren code
Da muss ich dir widersprechen.
document.getElementById("foo").getElementsByClassName("bar")[0];
ist IMHO um einiges übersichtlicher als
getElementsByClassName("bar",document.getElementById("foo"))[0];
…weil es die richtige Reihenfolge der Referenzierung wiedergibt. Das Mag bei diesem Beispiel noch nicht so stark in's Gewicht fallen, aber wenn die Schachtelungen immer tiefer werden, blickt man irgendwann nicht mehr durch.
mfg. Daniel
gruss Daniel,
eben, das ist durchaus der ansatz fuer schlankeren
Nö; Die Prototype-Variante ist - abgesehen von den IE-Würgarounds ...
davon laesst sich nicht absehen, denn darum geht es, um *genau einen*
*einheitlichen* code.
... auch nicht viel umfangreicher:
HTMLElement.prototype.getElementsByClassName = function(klasse){
var alles = this.getElementsByTagName("*");
…
}
das hat ja auch niemand in abrede gestellt. ich selbst habe seit jahren
erweiterungen in meiner code-ramschkiste, die auf prototypischen
erweiterungen von DOM elementen und/oder dem einsatz von \_\_getter\_\_,
\_\_setter\_\_ beruhen (z.b. fuer listen, collections, dictionaries ...).
die realitaet sieht aber anders aus, und nicht nur der msie unterstuetzt
diese features - denn das sind sie nunmal - nicht. kein browserhersteller
ist verpflichtet, die elemente des DOM wie native, durch den standard
ECMA-262, festgelegte JavaScript-objekte zu implementieren.
nachdem ich das endlich akzeptiert hatte, habe ich nach anderen
loesungen und loesungsansaetzen gesucht.
> > ... uebersichlicheren code
>
> Da muss ich dir widersprechen.
>
> `document.getElementById("foo").getElementsByClassName("bar")[0];`{:.language-javascript}
>
> ist IMHO um einiges übersichtlicher als
>
> `getElementsByClassName("bar",document.getElementById("foo"))[0];`{:.language-javascript}
>
> …weil es die richtige Reihenfolge der Referenzierung wiedergibt.
volle zustimmung - ich arbeite auch lieber mit dem punkt-operator.
> Das Mag bei diesem Beispiel noch nicht so stark in's Gewicht fallen,
> aber wenn die Schachtelungen immer tiefer werden, blickt man
> irgendwann nicht mehr durch.
richtig, aber das trifft auch auf den von Dir beschriebene idealfall
zu, wo es ebenfalls oft angebracht ist, solch langen referenzen
voruebergehend einer lokalen variablen aufzubuerden.
im uebrigen schaffen die grossen bibliotheken das von Dir kritisierte
stilistische merkmal ebenfalls nicht aus der welt; und einige nur dann,
solange man nicht den jeweils spezifischen namensraum verlaesst bzw.
die dort drinnen geltenden konventionen (und es sind immer andere)
bricht.
und genau aus diesen gruenden, und weil Felix' werkzeug \*nur\* ein
ordentlicher schraubendreher und kein profiwerkzeugkoffer sein wollte,
ist der von ihm eingeschlagene weg der fuer ihn direkt ins ziel fuehrende.
so long - peterS. - pseliger@gmx.net
--
»Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - [Douglas Crockford](http://javascript.crockford.com/)
ie:( fl:) br:> va:( ls:& fo:) rl:| n3;} n4:} ss:} de:µ js:} mo:? zu:]
Lieber peterS.,
~~~javascript
window.getElementsByClassName = function (className, element) {
var gefunden = [];
//if ((typeof className == "string") || (className instanceof String)) {
if (className) { // fliegt raus bei: [undefined], [null], [false], 0, "".//element = ((element && ((typeof element.getElementsByTagName == "function") || ((typeof element.getElementsByTagName == "object") && !obj))) ? (element) : (document));
element = ((element && element.getElementsByTagName) ? (element) : (document));var muster = new RegExp("(^|\s+)" + String(className) + "($|\s+)"); // typecast wenn nur ueber >>if (className) {<< geprueft
var alles = element.getElementsByTagName("*");
var i;
WOW! ich kapiere nichteinmal die Hälfte! Wenn [meine größten Sorgen mit den Browserunterschieden](https://forum.selfhtml.org/?t=152550&m=992304) bei meiner neuesten Spielerei beseitigt sind, dann werde ich mir das aus dem Archiv holen und gehörig reinziehen - versprochen!
Liebe Grüße aus [Ellwangen](http://www.ellwangen.de/),
Felix Riesterer.
--
ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
Hallo,
Und wie macht man dann den IE gefügig?
In der Praxis gar nicht - man nutzt Frameworks, die alle Elementobjekte, mit denen man arbeitet, individuell statt zentral on-the-fly mit solchen Zusatzmethoden ausstatten (Prototype, jQuery etc.).
Mathias
Lieber Mathias,
man nutzt Frameworks, die alle Elementobjekte, mit denen man arbeitet, individuell statt zentral on-the-fly mit solchen Zusatzmethoden ausstatten (Prototype, jQuery etc.).
OK, jetzt reicht's! So einen Schwachsinn tue ich mir nicht an. Dann doch lieber mit meinObjekt.getElementsByClassName(className, element)
...
Vielen Dank für Deine Hinweise!
Liebe Grüße aus Ellwangen,
Felix Riesterer.
OK, jetzt reicht's! So einen Schwachsinn tue ich mir nicht an. Dann doch lieber mit
meinObjekt.getElementsByClassName(className, element)
...
Der "Schwachsinn" ist aber eine durchaus übliche vorgehensweise bei komplexeren Anwendungen. Deshalb gibt es ja diese Bibliotheken, damit du dich nicht mehr um diesen "Schwachsinn" kümmern musst.
Struppi.
Hallo,
Der "Schwachsinn" ist aber eine durchaus übliche vorgehensweise bei komplexeren Anwendungen. Deshalb gibt es ja diese Bibliotheken, damit du dich nicht mehr um diesen "Schwachsinn" kümmern musst.
Genau. Es sollte auch erwähnt werden, dass die Bibliotheken auf Geschwindigkeit optimiert sind. Das heißt konkret, dass sie, wenn es der Browser erlaubt, XPath oder die Selectors-API verwenden. Dadurch können sie Standardoperationen wie getElementsByClassName extrem schnell umsetzen, weil sie auf getElementsByTagName("*"), das manuelle Durchlaufen der Knotenliste und auf das Vergleichen von className mittels regulären Ausdrücken verzichten.
Mathias
Hallo molily,
Object.prototype.getElementsByClassName
Wenn schon, dann HTMLElement.prototype, was aber IE bekanntlich auch nicht kann.
Hmm, stimmt, hatte ich nicht getestet.
Object.prototype zu erweitern ist nicht ohne und hat weitreichende Konsequenzen, daraufhin muss man jede for-in-Schleife mit einer hasOwnProperty-Abfrage versehen.
Nun, mit dieser Konsequenz könnte ich leben, da ich so gut wie nie diese Art von Schleife benötige - soll aber nicht heißen, das dies alle so machen ;-)
Also lieber Finger weg davon, wenns auch anders geht.
Ich merks mir ;-)
Mit freundlichem Gruß
Micha
Hallo Felix.
ich brauche manchmal die Funktion document.getElementsByClassName(), die jedoch nicht im bisherigen Javascript-Sprachumfang implementiert ist.
Du solltest dir bei Gelegenheit dazu auch Peter Seligers JS-Bibliothek anschauen.
Einen schönen Dienstag noch.
Gruß, Mathias
Lieber Mathias,
Du solltest dir bei Gelegenheit dazu auch Peter Seligers JS-Bibliothek anschauen.
von der habe ich auch schon gelesen, aber ich hätte es gerne selbst verstanden und geschrieben. Peters Bibliothek zu verwenden (die ich nicht wirklich verstehe!) würde bedeuten, mich auf Code zu verlassen, den ich nicht selbst geschrieben habe, und den ich im Zweifelsfalle nicht selbst erfolgreich debuggen könnte.
Ich hätte es gerne selbst gekonnt (und verstanden!), wenn Du verstehst, was ich meine. :-)
Liebe Grüße aus Ellwangen,
Felix Riesterer.
gruss Felix
... aber ich hätte es gerne selbst verstanden und geschrieben.
das ehrt Dich. und damit ich von diesem lob auch etwas abbekomme,
gestehe ich, dass dieses *selbst* auch der meinereinige antrieb ist.
Peters Bibliothek zu verwenden (die ich nicht wirklich verstehe!)
ach komm, so kompliziert ist das ding gar nicht.
unter anderem werden dem [[Array]]-konstruktor sowohl statische als
auch prototypische accessoren und iteratoren beigebracht, sofern er
diese noch nicht kennen sollte bzw. sobald ich der meinung bin, dass
meine auslegung besser ist als die der mozilla.org.
falls die (nicht instanziierbaren) *DOM-klassen* [[NodeList]] bzw.
[[Node]] nicht existieren - keine ahnung, wie ich das korrekt
beschreiben soll - kurz und gut, falls also weder ein wie auch
immer geartetes [NodeList]- bzw. [Node]-objekt existiert, werden in
einem der ersten schritte einfache objektinstanzen auf den globalen
variablen [NodeList] bzw. [Node] erzeugt.
sowohl das [document]-objekt als auch die jetzt existierenden beiden
oben genannten werden nun um jeweil gleichlautende DOM-methoden
erweitert, das problem anerkennend, dass es einfach keine vernuenftige
und browseruebergreifend performante loesung dafuer gibt, DOM-objekte
im nachhinein fuer selbstgestrickte methoden zu erwaermen.
und genau dieses problem erwartet dich ja auch, wenn Du Deine eigene,
unkompliziert an das [document]-objekt getackerte methode jetzt auch
noch jedem einzelnen DOM-Knoten angedeihen lassen moechtest.
weiterhin finde ich es problematisch, dass die browseruebergreifenden
loesungen, die so tun, als ob sie genau dies leisteten, dann eben doch
keine echten [NodeList]s oder [HTMLCollection]s zurueckliefern.
das problem wird dann mit einer armada von geschwindigkeitshemmenden
und codeaufblaehenden wrapper-objekten erschlagen oder einfach gleich
ignoriert.
und das sind bei weitem nicht alle gruende dafuer, warum der von mir
favorisierte loesungsansatz ein voellig anderer ist.
würde bedeuten, mich auf Code zu verlassen, den ich nicht selbst
geschrieben habe, und den ich im Zweifelsfalle nicht selbst
erfolgreich debuggen könnte.
richtig!
Du solltest dir bei Gelegenheit dazu auch Peter Seligers JS-Bibliothek
anschauen.
@all:
im uebrigen sind mir keine weiteren erfahrungsberichte ueber den
einsatz dieser script-pakete zugeflossen - die welt sowiso und
auch das forum koennen also ganz gut ohne solchen kram leben.
so long - peterS. - pseliger@gmx.net