Andrea 97: HTML-Collections => Arrays: Reihenfolge?

Hallo SelfHTML Gemeinde!

Ich habe eine Frage zu HTML-Collections von getElementsByClassName()!

Wenn ich diese in ein Array konvertiere, kann ich mich drauf verlassen, dass dann Array[0] immer das erste Element im Markup, Array[1] immer das zweite, usw. ist?

Oder ist da wie bei Objekten die Reihenfolge egal?

Vielen lieben Dank, Eure Andi!

  1. Ich habe eine Frage zu HTML-Collections von getElementsByClassName()!

    Aha.

    Wenn ich diese in ein Array konvertiere,

    Wozu willst Du das tun? MDN beschreibt die HTML-Collections als Array-ähnliche Sammlung.

    kann ich mich drauf verlassen, dass dann Array[0] immer das erste Element im Markup, Array[1] immer das zweite, usw. ist?

    Nicht wenn Du mit JS schon am DOM herumgefummelt hast…

    1. Aber ich kann ja nicht über HTML-Collections iterieren! :(

      z.B. forEach, etc.

      ...und ja, die Reihenfolge wurde natürlich noch nicht via Javascript vertauscht!

      1. Aber ich kann ja nicht über HTML-Collections iterieren! :(

        Soso…

        1. Wo siehstn du da ein forEach?

          1. Wo siehstn du da ein forEach?

            Willst Du nun über die HTML-Collection iterieren oder über die Hilfe meckern?

            1. Welche Hilfe?

              Ich weiß jetzt immer noch nicht, ob die Reihenfolge im Markup übernommen wird, wenn ich über HTML-Collection Arrays iteriere

              1. Welche Hilfe?

                Nun, ich habe Dir gezeigt, wo steht, wie Du über die die HTML-Collection iterieren kannst. Wie das geht wolltest Du wissen - hast jedenfalls behauptet, Du könntest es nicht.

                Ich weiß jetzt immer noch nicht, ob die Reihenfolge im Markup übernommen wird, wenn ich über HTML-Collection Arrays iteriere

                https://dom.spec.whatwg.org/#htmlcollection sagt:

                „The elements are sorted in tree order.“

                Mindestens dann, wenn Deine Elemente alle direkte Kinder ein und desselben Parent-Elements im DOM-Baum („tree“ heißt „Zweig“) sind, dann trifft das demnach zu.

                1. Jörg, getElementsByClassName liefert eine HTMLCollection, keine NodeList. Die forEach Methode gibt's nur in der NodeList.

                  Man könnte statt getElementsByClassName("foo") auf querySelectorAll(".foo") ausweichen, DER liefert eine Nodelist und da gibt's dann forEach. Außer im Internet Explorer, der will einen Polyfill.

                  Rolf

                  --
                  sumpsi - posui - obstruxi
                2. Ok, danke danke danke!

                  Das heißt also laut https://dom.spec.whatwg.org/#htmlcollection

                  <parent>
                  	<el_1>
                  	<el_2>
                  	<el_3>
                  </parent>
                  

                  ergibt die Reihenfolge: HTMLCollection → <el_1> → <el_2> → <el_3>

                  während aber z.B.

                  <parent>
                  	<subparent>
                  		<el_1>
                  		<el_2>
                  	</subparent>
                  </parent>
                  <parent>
                  	<el_3>
                  </parent>
                  

                  die Reihenfolge HTMLCollection → <el_3> → <el_1> → <el_2> ergibt?

                  1. Hallo Andrea 97,

                    Das heißt also laut https://dom.spec.whatwg.org/#htmlcollection
                    […]
                    ergibt die Reihenfolge: HTMLCollection → <el_1> → <el_2> → <el_3>
                    während aber z.B.
                    […]
                    die Reihenfolge HTMLCollection → <el_3> → <el_1> → <el_2> ergibt?

                    Das kann man ja einfach mal ausprobieren und in den Browsern testen.

                    Bis demnächst
                    Matthias

                    --
                    Du kannst das Projekt SELFHTML unterstützen,
                    indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
                  2. Jörg, danke für den Link. Das hab ich übersehen.

                    Hallo Andrea,

                    nein. Die Spec definiert tree order so:

                    In tree order is preorder, depth-first traversal of a tree.

                    Preorder heißt: Zuerst das Root, dann die Children. Und das rekursiv pro Kind.

                    Wäre in deinem zweiten Beispiel:

                    root (body)
                    parent 1
                    subparent 1
                    el_1
                    el_2
                    parent 2
                    el_3

                    Rolf

                    --
                    sumpsi - posui - obstruxi
      2. @@Andrea 97

        Aber ich kann ja nicht über HTML-Collections iterieren! :(

        Nicht mit forEach, aber mit for … of

        Guckst du.

        🖖 Stay hard! Stay hungry! Stay alive! Stay home!

        --
        Vielen Eltern dämmert beim Home-Schooling so langsam die Erkenntnis: Lehrer ist wohl doch ein regelrechter Beruf! (@heuteshow)
        1. Aber ich kann ja nicht über HTML-Collections iterieren! :(

          Nicht mit forEach, aber mit for … of

          Guckst du.

          Nur der Vollständigkeit halber:

          Mit forEach geht es auch; z.B. für Browser ohne for..of Unterstützung.

          // bezieht sich auf Gunnars codePen
          Array.prototype.forEach.call(
              nephewsNodeList,
              function(nephew) {
                  nephew.style.border = '2px dotted red';
              }
          );
          
          --
          Stur lächeln und winken, Männer!
          1. @@kai345

            // bezieht sich auf Gunnars codePen
            Array.prototype.forEach.call(
                nephewsNodeList,
                function(nephew) {
                    nephew.style.border = '2px dotted red';
                }
            );
            

            Für NodeList braucht man das nicht; du meintest nephewsHTMLCollection:

            Array.prototype.forEach.call(
                nephewsHTMLCollection,
                function(nephew) {
                    nephew.style.border = '2px dotted red';
                }
            );
            
            

            oder auch

            Array.prototype.forEach.call(
                nephewsHTMLCollection,
                nephew => {
                    nephew.style.border = '2px dotted red';
                }
            );
            

            HTMLCollection in Array umwandeln kann man so haben:

            Array.from(nephewsHTMLCollection).forEach(nephew => {
            	nephew.style.textDecoration = 'underline';
            });
            

            oder kurz

            [...nephewsHTMLCollection].forEach(nephew => {
            	nephew.style.textDecoration = 'underline';
            });
            

            🖖 Stay hard! Stay hungry! Stay alive! Stay home!

            --
            Vielen Eltern dämmert beim Home-Schooling so langsam die Erkenntnis: Lehrer ist wohl doch ein regelrechter Beruf! (@heuteshow)
  2. Hallo,

    Iterieren über eine Collection geht auch mit der for-Schleife.

    Bisher haben bei mir die getElemets-Methoden die Elemente immer in der Reihenfolge wie im html geliefert. Ob das so sein muss, weiß ich aber nicht genau. Warum ist denn die Reihenfolge wichtig?

    Gruß
    Jürgen

  3. Hallo Andrea,

    wie schon von Raketenjörg gesagt - ein Array braucht es nicht unbedingt.

    ES SEI DENN, du willst in der Schleife das DOM verändern. Dann brauchst Du eventuell das Array, weil die HTMLCollection live ist, die spiegelt Änderungen am DOM sofort wieder.

    Aber bevor Du das tust, verwende lieber querySelectorAll. Diese Methode liefert Dir eine statische Nodelist. D.h. sie friert den Zustand des DOM in dem Moment, wo die Abfrage stattfand, ein.

    document.getElementsByClassName("foo")  
    

    und

    document.querySelectorAll(".foo")  
    

    liefern beide alle Elemente mit Klasse foo. Ersteres als live HTMLCollection, letzteres als statische NodeList, die auch mehr Methoden anbietet.

    Eine Reihenfolgegarantie kann ich Dir aber auch nicht geben. Ich finde in der HTML DOM Spezifikation keine Definition dazu. Demnach ist der Browser frei, das Ergebnis nach Belieben zu verwürfeln. Das muss er natürlich nicht tun. Er kann auch eine prefix-Traversierung des DOM Baums vornehmen, die die Elemente in der Reihenfolge liefert wie sie im Sourcecode stehen (ja, ich weiß, wenn man am DOM rumgefummelt hat entspricht es nicht mehr dem Sourcecode).

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Ok, danke!

    2. Eine Reihenfolgegarantie kann ich Dir aber auch nicht geben. Ich finde in der HTML DOM Spezifikation keine Definition dazu.

      Du hast vermutlich bei der NodeList gesucht, bei querySelectorAll wird man fündig, wenn man den Links folgt.

      The querySelectorAll(selectors) method, when invoked, must return the static result of running scope-match a selectors string selectors against this.

      Return the result of match a selector against a tree with s and node’s root using scoping root node.

      Start with a list of candidate elements, which are the the root elements and all of their descendant elements, sorted in shadow-including tree order, unless otherwise specified.

      In shadow-including tree order is shadow-including preorder, depth-first traversal of a node tree.