Felix Riesterer: Objekt aus getElementsByTagName() erweitern?

Liebe Selfer,

ich habe mir mit document.getElementsByTagName("ul") alle <ul>s ermitteln lassen. Diese Funktion gibt mir nicht etwa - wie ich so blauäugig erwartet hätte - ein Array mit den Referenzen zu den HTML-Elementen zurück, sondern ein "object". Aber dieses Objekt kann ich (wie eben ein Array) mit einem Index abfragen und so auf die Elemente zugreifen:

var alle_uls = document.getElementsByTagName("ul");  
for (var index = 0; index < alle_uls.length; index++) { alle_uls[index].tue_was(); }

Nun habe ich ein weiteres Objekt, das ich in einer Schleife gerne ebenso behandeln möchte, wie alle diese alle_uls[index]. Dazu habe ich mit alle_uls[alle_uls.length] = mein_objekt das aus der oben genannten Funktion gewonnene Objekt um genau diesen Knoten erweitert.

Warum geht denn nun die Eigenschaft length nicht um einen Zähler hoch? Ich kann in der Schleife (siehe oben) zwar alle <ul>-Elemente abfragen, aber wenn ich auf "index < alle_uls.length" prüfen lasse, dann bricht die Schleife um genau das neu angehängte Objekt zu früh ab. Eine Prüfung auf "index <= alle_uls.length" behebt das Problem zwar einigermaßen, aber bei mir bleibt die Frage, warum denn da die length nicht um eins erhöht wurde, bzw. was ich hätte tun können, damit dem so ist.

Kurze Versuche mit alle_uls.appendChild(mein_objekt) und alle_uls.insertBefore(mein_objekt, alle_uls[alle_uls.length]) sind gescheitert, da ich sie wohl im falschen Kontext verwendet habe.

Durch meine Objektmanipulationen wird die von Javascript erzeugte Aussage über die Anzahl im Dokument vorhandener <ul>-Elemente völlig zweckentfremdet, das ist klar. Aber ein neues Objekt zu definieren, in das ich dann alles "hinüberkopiere" empfinde ich als nicht besonders praktisch... Und außerdem habe ich ja eine Variablen "alle_uls" mit einer Kopie des von der Funktion getElementsByTagName zurückgegebenen Wertes gefüttert. Damit wäre mein Vorgehen ja nicht verwerflich...

Wer kann mich über die tiefen Geheimnisse aufklären?

Liebe Grüße aus Ellwangen,

Felix Riesterer.

  1. ich habe mir mit document.getElementsByTagName("ul") alle <ul>s ermitteln lassen. Diese Funktion gibt mir nicht etwa - wie ich so blauäugig erwartet hätte - ein Array mit den Referenzen zu den HTML-Elementen zurück, sondern ein "object". Aber dieses Objekt kann ich (wie eben ein Array) mit einem Index abfragen und so auf die Elemente zugreifen:

    Es ist eine HTMLCollection

    Warum geht denn nun die Eigenschaft length nicht um einen Zähler hoch? I

    Weil es kene Array ist. Du kannst vielleicht length von Hand erhöhen (grad keine Lust zu probieren).

    Durch meine Objektmanipulationen wird die von Javascript erzeugte Aussage über die Anzahl im Dokument vorhandener <ul>-Elemente völlig zweckentfremdet, das ist klar. Aber ein neues Objekt zu definieren, in das ich dann alles "hinüberkopiere" empfinde ich als nicht besonders praktisch... Und außerdem habe ich ja eine Variablen "alle_uls" mit einer Kopie des von der Funktion getElementsByTagName zurückgegebenen Wertes gefüttert. Damit wäre mein Vorgehen ja nicht verwerflich...

    Soweit ich weiß benutzt JS Referenzen bei Objekten, d.h. wenn du die Objekte in eine eigenes Array kopierst, werden keine Kopien angelegt, sondern nur die Referenz auf das Objekt. Insofern wäre das durchaus nicht unpraktisch, wenn du unbedingt es so machen willst.

    Struppi.

    1. Hallo Struppi,

      Soweit ich weiß benutzt JS Referenzen bei Objekten, d.h. wenn du die Objekte in eine eigenes Array kopierst, werden keine Kopien angelegt, sondern nur die Referenz auf das Objekt. Insofern wäre das durchaus nicht unpraktisch, wenn du unbedingt es so machen willst.

      Habe selbst mal experimentiert, weil ich neugierig war, ob man über diese Kopie denn dann überhaupt auch noch Zugriff auf das eigentliche, ursprüngliche Objekt hat. Das verblüfft mich jetzt zwar, aber es ist wohl so:

        
      <!doctype html public "-//W3C//DTD HTML 4.0 //EN">  
      <html>  
      <head>  
      <title>concatObjects</title>  
      <meta name="author" content="Gernot Back">  
      <meta name="generator" content="Ulli Meybohms HTML EDITOR">  
      <script type="text/javascript">  
      [code lang=javascript]  
      function init () {  
        alleUllis = new Array();  
        alleOllis = document.getElementsByTagName('OL')[0].getElementsByTagName('LI');  
        for (i=0; i<alleOllis.length ; i++ ) {  
           alert(alleOllis[i].innerHTML);  
        }  
        alleOllis = new Array();  
        for (i=0; i<document.getElementsByTagName('UL')[0].getElementsByTagName('LI').length ; i++ ) {  
          alleUllis[i]=document.getElementsByTagName('UL')[0].getElementsByTagName('LI')[i];  
        }  
        for (i=0; i<document.getElementsByTagName('OL')[0].getElementsByTagName('LI').length ; i++ ) {  
          alleOllis[i]=document.getElementsByTagName('OL')[0].getElementsByTagName('LI')[i];  
        }  
        alert(alleUllis.length + '\n' + alleOllis.length)  
        alleLillis = alleUllis.concat(alleOllis);  
        alert(alleLillis);  
        for (i=0; i<alleLillis.length ; i++ ) {  
           alert(alleLillis[i].innerHTML);  
           alleLillis[i].innerHTML="bla";  
        }  
      }  
      window.onload=init;
      

      </script>
      </head>
      <body>
      <ul>
      <li>a</li>
      <li>b</li>
      <li>c</li>
      <li>d</li>
      </ul>

      <ol start="1" type="1">
      <li>eins</li>
      <li>zwei</li>
      <li>drei</li>
      <li>vier</li>
      </ol>
      </body>
      </html>
      [/code]

      Gruß Gernot

      1. Hallo Gernot Back

        Hallo Struppi,

        Soweit ich weiß benutzt JS Referenzen bei Objekten, d.h. wenn du die Objekte in eine eigenes Array kopierst, werden keine Kopien angelegt, sondern nur die Referenz auf das Objekt. Insofern wäre das durchaus nicht unpraktisch, wenn du unbedingt es so machen willst.

        Habe selbst mal experimentiert, weil ich neugierig war, ob man über diese Kopie denn dann überhaupt auch noch Zugriff auf das eigentliche, ursprüngliche Objekt hat. Das verblüfft mich jetzt zwar, aber es ist wohl so:

        Ich hatte es auch vorher ausprobiert ;-)

        Allerdings mit einem Array, da vermutlich alles was ein Object ist, nicht kopiert wird.

        var a = new Array(1,2,3);
        var b = a;
        b[0] = 20;

        alert(a + '\n' + b);

        Struppi.

        1. Hallo Struppi,

          das heißt aber doch im Klartext, dass auch wir bei unseren Experimenten hier nicht mit einer Kopie eines Objekts arbeiten, sondern mit der Kopie einer Referenz auf dasselbe Objekt. Siehst du das genauso?

          Gruß Gernot

          1. das heißt aber doch im Klartext, dass auch wir bei unseren Experimenten hier nicht mit einer Kopie eines Objekts arbeiten, sondern mit der Kopie einer Referenz auf dasselbe Objekt. Siehst du das genauso?

            Genau.

            Alles andere wäre auch ziemlich aufwendig, einmal künnte sich - gerde bei Arrays - der Speicherverbrauch enorm erhöhen, wenn du jedesmal eine 1:1 Kopie erstellst und ist eine Kopie eines komplexen Objektes ja auch keine einfache Sache.

            Du brauchst für jedes Objekt einen copy Konstruktor, der alle Attribute übernimmt. D.h. wenn du sowas machst:

            var win = window;

            müssen alle Eigenschaften von window und dessen Unterobjekte (und dessen Unterobjekte usw, wobei man da nicht im Kreis gehen darf, da z.b. self wieder gleich window ist und window.parent ebenfalls) nach win kopiert werden.

            Struppi.

            1. Lieber Struppi und lieber Gernot,

              vielen Dank für Eure Hinweise und Erläuterungen! Ich bin schon deutlich weiter gekommen. Wenn ich nun das von Euch Gesagte zusammenfassen darf, dann ergibt sich daraus das Folgende.

              Also:

              Es handelt sich bei der Rückgabe von document.getElementsByXYZ um eine HTMLCollection, die man zwar ähnlich wie ein Array über einen numerischen Index auslesen kann, die aber kein solches ist. Ein Array speichert Werte, diese Collection jedoch nur Referenzen auf Objekte.

              Dadurch kann ich zwar dieser HTMLCollection neue Eigenschaften verpassen, wie zum Beispiel eine Eigenschaft mit einem numerischen Bezeichner, dessen absoluter Wert höher ist, als die (Pseudo-)Indices des Rückgabewertes, jedoch ändert sich die Eigenschaft length deswegen nicht. Sie ist ausserdem anscheinend nur lesbar, nicht aber beschreibbar (im FF ausprobiert => is a "getter"). Davon unberührt bleibt die Zugriffsmöglichkeit auf diese neue Eigenschaft.

              Ist das so richtig?

              Liebe Grüße aus Ellwangen,

              Felix Riesterer.

              1. Also:

                Es handelt sich bei der Rückgabe von document.getElementsByXYZ um eine HTMLCollection, die man zwar ähnlich wie ein Array über einen numerischen Index auslesen kann, die aber kein solches ist. Ein Array speichert Werte, diese Collection jedoch nur Referenzen auf Objekte.

                Genaueres hier:
                http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html#ID-75708506

                Dadurch kann ich zwar dieser HTMLCollection neue Eigenschaften verpassen, wie zum Beispiel eine Eigenschaft mit einem numerischen Bezeichner, dessen absoluter Wert höher ist, als die (Pseudo-)Indices des Rückgabewertes, jedoch ändert sich die Eigenschaft length deswegen nicht. Sie ist ausserdem anscheinend nur lesbar, nicht aber beschreibbar (im FF ausprobiert => is a "getter"). Davon unberührt bleibt die Zugriffsmöglichkeit auf diese neue Eigenschaft.

                letzteres steht auch oben.

                Du kannst jedem Object neue Eigenschaften verpassen. Eine HTML Collection hat einfach nicht die Eigenschaften eines Arrays.

                Ist das so richtig?

                Soweit ja.

                Mach ruhig eine Kopie in einem Array wenn du das wirklich brauchst.

                Struppi.

              2. Es handelt sich bei der Rückgabe von document.getElementsByXYZ um eine HTMLCollection, die man zwar ähnlich wie ein Array über einen numerischen Index auslesen kann, die aber kein solches ist. Ein Array speichert Werte, diese Collection jedoch nur Referenzen auf Objekte.

                Was heißt »Werte«? Ein Array definiert sich nicht darüber, was er speichert. Das können primitive values sein, aber auch Objekte bzw. Referenzen auf Objekte.
                Eine HTMLCollection ist einfach ein Objekt mit bestimmten Methoden und Eigenschaften. Zur Vereinfachung definiert DOM HTML, dass die item- und namedItem-Methode in ECMAScript-Sprachen mit collection["name"] bzw. collection[123] angesprochen werden können.

                Mathias