Onkel Schnitzel: JSON.stringify mit mehrdimensionalem Array -> undefined

Mahlzeit,

ich versuche gerade mein schönes zusammengefrickeltes Array JSON-fertig zu machen, aber JSON.stringify() liefert mir ein undefined. Testweise habe ich mal mit dem selfhtml-Mitarbeiter-Beispiel rumgespielt und damit funktionierts - sowohl mit assoziativer Variante als auch mit echtem numerischem Array. So sieht die Ausgabe des Mitarbeiter-Arrays in der Konsole aus:

[Array[4], Array[4]]
  0: Array[4]
    1: "Müller"
    2: "Hans"
    3: "Dresden"
    length: 4
    __proto__: Array[0]
  1: Array[4]
    1: "Schulze"
    2: "Frauke"
    3: "Berlin"
    length: 4
    __proto__: Array[0]
  length: 2
  __proto__: Array[0]

Und so mein Array, das ein undefined liefert:

[4: Array[8], 10: Array[8], 11: Array[8], 18: Array[8], 19: Array[8], 27: Array[8], 28: Array[8]]
  4: Array[8]
    0: 0
    1: 0
    2: 0
    3: 0
    4: 0
    5: 0
    6: 0
    7: 0
    length: 8
    __proto__: Array[0]
  10: Array[8]
    0: 0
    1: 0
    2: 0
    3: 0
    4: 0
    5: 0
    6: 0
    7: 0
    length: 8
    __proto__: Array[0]

......

length: 29
  __proto__: Array[0]

Was auffällt, ist, dass in meiner Variante die Schreibweise der ersten Zeile etwas anders ist (jeweils noch mal der Wert des allerersten Keys vor dem Unterarray) und dass die length mit 29 angegeben ist, obwohl das Array in der ersten Ebene nur 7 Objekte/Arrays hat. Auch das testweise Durchlaufen der ersten Ebene mit for (n in array) geschieht nur 7mal.

Irgendwie habe ich aber das Gefühl, dass das Problem mit stringify daher rührt, dass mit dem Array etwas nicht stimmt. Hat jemand eine Idee? Vor allem, wo die length:29 herkommen könnte?

Gruß

Onkel Schnitzel

  1. Meine Herren!

    Testweise habe ich mal mit dem selfhtml-Mitarbeiter-Beispiel rumgespielt und damit funktionierts

    Link?

    sowohl mit assoziativer Variante als auch mit echtem numerischem Array.

    Assoziative Arrays gibt es in JavaScript nicht. Es ist zwar problemlos möglich einem Array eine benannte Eigenschaft zuzuweisen, aber diese Eigenschaft erfüllt dann nicht die Bedingungen einen Array-Elements. Herkömmliche Array-Methoden, wie indexOf oder forEach ignorieren diese Eigenschaft zum Beispiel.

    und dass die length mit 29 angegeben ist, obwohl das Array in der ersten Ebene nur 7 Objekte/Arrays hat.

    Die length-Eigenschaft entspricht dem höchsten vergebenen Array-Index + 1. Also gilt zum Beispiel auch:

    var myArray = [];  
    myArray[99] = 'foo';  
    myArray.length === 100; // true
    

    Auch das testweise Durchlaufen der ersten Ebene mit for (n in array) geschieht nur 7mal.

    for-in-Schleifen iterieren über Eigenschaften eines Objekts, die das "enumerable" Flag gesetzt haben, und dabei werden Eigenschaften aus der Prototyp-Kette eingeschlossen. Um über Arrays zu iterieren bietet sich in erster Linie die Methode .forEach() an, oder eine normale for-Schleife.

    Irgendwie habe ich aber das Gefühl, dass das Problem mit stringify daher rührt, dass mit dem Array etwas nicht stimmt. Hat jemand eine Idee?

    Zeig uns doch mal den Code, mit dem das Array erstellt und befüllt wird.

    1. Link?

      http://de.selfhtml.org/javascript/objekte/array.htm#assoziative_arrays

      Die length-Eigenschaft entspricht dem höchsten vergebenen Array-Index + 1. Also gilt zum Beispiel auch:

      Aah, ok, das erklärt die 29 natürlich. Aber da hätte ich mal auch drauf kommen können :-/

      for-in-Schleifen iterieren über Eigenschaften eines Objekts, die das "enumerable" Flag gesetzt haben, und dabei werden Eigenschaften aus der Prototyp-Kette eingeschlossen. Um über Arrays zu iterieren bietet sich in erster Linie die Methode .forEach() an, oder eine normale for-Schleife.

      Ooh, ist .forEach() neu? Ich dachte sowas gibts nicht in JS. Ich kannte sonst bloß noch den Weg über for(i, i < array.length, i++).

      Zeig uns doch mal den Code, mit dem das Array erstellt und befüllt wird.

        
      function createSpielerdatenArray(id,spielzeit,eingew,ausgew,tore,gelb,gelb_rot,rot) {  
      	SpielerdatenArray[id] = new Array;  
      	if(spielzeit > 0) {  
      	SpielerdatenArray[id][0] = 1;  
      	}  
      	else {  
      	SpielerdatenArray[id][0] = 0;			  
      	}  
      	SpielerdatenArray[id][1] = spielzeit;				  
      	SpielerdatenArray[id][2] = eingew;				  
      	SpielerdatenArray[id][3] = ausgew;				  
      	SpielerdatenArray[id][4] = tore;				  
      	SpielerdatenArray[id][5] = gelb;				  
      	SpielerdatenArray[id][6] = gelb_rot;				  
      	SpielerdatenArray[id][7] = rot;  
      }  
      
      

      Die Funktion befindet sich in einer while-Schleife einer MySQL-Abfrage und wird bei jedem Durchlauf aufgerufen und mit den entsprechenden Werten aus der DB gefüllt.

      Gruß

      Onkel Schnitzel

      1. Meine Herren!

        Ooh, ist .forEach() neu? Ich dachte sowas gibts nicht in JS. Ich kannte sonst bloß noch den Weg über for(i, i < array.length, i++).

        Mit Semikolon als Trenner, aber ja. forEach ist noch nicht so alt, ist aber leicht nachrüstbar auch für ältere Browser.

        Also dein Code macht in einem kleinen Test keine Schwierigkeiten.

        Die Funktion befindet sich in einer while-Schleife einer MySQL-Abfrage und wird bei jedem Durchlauf aufgerufen und mit den entsprechenden Werten aus der DB gefüllt.

        Huch, läuft dein JavaScript auf dem Server (Node.js o.Ä)? Sonst frage ich mich, wie du über eine MySQL-Ergebnis-Menge iterierst.

        Über deine Software-Architektur hat molily ja schon ein paar Worte verloren, deshalb spar ich mir das.

        1. Also dein Code macht in einem kleinen Test keine Schwierigkeiten.

          Ja, das sieht gut aus.

          Die Funktion befindet sich in einer while-Schleife einer MySQL-Abfrage und wird bei jedem Durchlauf aufgerufen und mit den entsprechenden Werten aus der DB gefüllt.

          Huch, läuft dein JavaScript auf dem Server (Node.js o.Ä)? Sonst frage ich mich, wie du über eine MySQL-Ergebnis-Menge iterierst.

          Nee, ganz normales JavaScript. In der while-Schleife (PHP, das hätte ich vielleicht dazuschreiben sollen), befindet sich ein Script-Bereich mit der Funktion:

            
          createSpielerdatenArray(<?=$id?>,<?=$spielzeit?>,<?=$eingew?>,<?=$ausgew?>,<?=$tore?>,<?=$gelb?>,<?=$gelb_rot?>,<?=$rot?>);  
          
          

          Zur Zeit wird genau das hier erzeugt:

            
          createSpielerdatenArray(28,0,0,0,0,0,0,0);  
          createSpielerdatenArray(19,0,0,0,0,0,0,0);  
          createSpielerdatenArray(27,0,0,0,0,0,0,0);  
          createSpielerdatenArray(11,0,0,0,0,0,0,0);  
          createSpielerdatenArray(4,0,0,0,0,0,0,0);  
          createSpielerdatenArray(10,0,0,0,0,0,0,0);  
          createSpielerdatenArray(18,0,0,0,0,0,0,0);  
          
          

          Das liefert mir dann in deiner Testdatei auch das gleiche Array, wie in meinem Script. Nur das in der Testfile JSON.stringify funktioniert, im Gegensatz zu meinem Script...

          Ach herrje! Was fürn seltendämlicher Fehler wieder. Statt diesem hier:

            
          var SpielerdatenStr = JSON.stringify(SpielerdatenArray);  
          console.log(SpielerdatenStr);  
          
          

          Hatte ich das geschrieben:

            
          var SpielerdatenArray = JSON.stringify(SpielerdatenArray);  
          console.log(SpielerdatenArray);  
          
          

          Das darf man ja niemandem erzählen! Wie peinlich... Naja, auf jeden Fall liefert mir die Konsole jetzt folgenden String:

          [null,null,null,null,[0,0,0,0,0,0,0,0],null,null,null,null,null,[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],null,null,null,null,null,null,[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],null,null,null,null,null,null,null,[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0]]

          Das sieht ja sehr abenteuerlich aus. Ohne es jetzt schon getestet zu haben, habe ich irgendwie kein gutes Gefühl, dass mir mein PHP-Script daraus wieder das Array zusammenbasteln wird.

          Besten Dank auf jeden Fall erstmal schonmal

          Onkel Schnitzel

          1. Ach herrje! Was fürn seltendämlicher Fehler wieder. Statt diesem hier:

            var SpielerdatenStr = JSON.stringify(SpielerdatenArray);
            console.log(SpielerdatenStr);

            
            >   
            > Hatte ich das geschrieben:  
            >   
            > ~~~javascript
              
            
            > var SpielerdatenArray = JSON.stringify(SpielerdatenArray);  
            > console.log(SpielerdatenArray);  
            > 
            
            

            Bzw. hätte ich das natürlich nicht nochmal neu mit var deklarieren dürfen.

            Gruß

            Onkel Schnitzel

          2. Meine Herren!

            Nee, ganz normales JavaScript. In der while-Schleife (PHP, das hätte ich vielleicht dazuschreiben sollen), befindet sich ein Script-Bereich mit der Funktion:

            createSpielerdatenArray(<?=$id?>,<?=$spielzeit?>,<?=$eingew?>,<?=$ausgew?>,<?=$tore?>,<?=$gelb?>,<?=$gelb_rot?>,<?=$rot?>);

              
            Okay, du merkst sicherlich selber, dass du dir damit keinen Gefallen tust. Technisch betrachtet generierst du mit PHP JavaScript-Code. Damit erschaffst du ein unkontrollierbares Ungeheuer, das Hunde-Welpen tötet.  
              
            
            > Zur Zeit wird genau das hier erzeugt:  
            >   
            > ~~~javascript
              
            
            > createSpielerdatenArray(28,0,0,0,0,0,0,0);  
            > createSpielerdatenArray(19,0,0,0,0,0,0,0);  
            > createSpielerdatenArray(27,0,0,0,0,0,0,0);  
            > createSpielerdatenArray(11,0,0,0,0,0,0,0);  
            > createSpielerdatenArray(4,0,0,0,0,0,0,0);  
            > createSpielerdatenArray(10,0,0,0,0,0,0,0);  
            > createSpielerdatenArray(18,0,0,0,0,0,0,0);  
            > 
            
            

            Den ersten Parameter benutzt du als Array-Index in deinem JavaScript-Modell. Wenn diese Indizes nicht unmittelbar aufeinander folgen erzeugst du damit Löscher in deinem Array. Und Löschern muss man sich immer mit besonderer Aufmerksamkeit widmen, damit hast du ja schon Erfahrungen gemacht (length-Eigenschaft). Du kannst jetzt die Löscher bestehen lassen und Ausnahmenbehandlungen an allen Ecken und Enden hinzufügen, oder du passt deine Datenstruktur dahingehend an, dass sie keine Löscher mehr enthält.

            [null,null,null,null,[0,0,0,0,0,0,0,0],null,null,null,null,null,[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],null,null,null,null,null,null,[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],null,null,null,null,null,null,null,[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0]]

            Das sieht ja sehr abenteuerlich aus.

            null steht überall da, wo dein Array eine Lücke hat.

            Ohne es jetzt schon getestet zu haben, habe ich irgendwie kein gutes Gefühl, dass mir mein PHP-Script daraus wieder das Array zusammenbasteln wird.

            Das heißt, du hast vor mit deinem JavaScript Daten an den Server zu übermitteln und du benutzt dazu JSON als Austauschformat. Das ist ne feine Sache, wenn du das noch weiterspinnst kommt dir vielleicht irgendwann der Gedanke, dass dein JavaScript sich die Daten auch schon im JSON-Format vom Server abholen kann. Damit kannst du den Hunde-Welpen-Killer wieder bändigen.

            --
            “All right, then, I'll go to hell.”
            1. Meine Herren!

              Das konnte ich so nicht stehen lassen, auch als Rheinländer kann man sich zumindest bei der Rechtschreibung bemühen, wenn es mit der Aussprache schon nicht klappt.

              --
              “All right, then, I'll go to hell.”
              1. Das konnte ich so nicht stehen lassen, auch als Rheinländer kann man sich zumindest bei der Rechtschreibung bemühen, wenn es mit der Aussprache schon nicht klappt.

                Ich dachte das is ne Berliner Unart :-)

            2. Technisch betrachtet generierst du mit PHP JavaScript-Code.

              Ist das generell zu ächten? Ich fand das jetzt sehr praktisch, weil ich mein sqlResult ja ohnehin per while durchlaufe. Und in dem Zuge dachte ich mir, könnte ich auch mein JS-Array mit den Daten befüllen.

              Damit erschaffst du ein unkontrollierbares Ungeheuer, das Hunde-Welpen tötet.

              Ach herrje. Mit Hunden hab ichs zwar nich so, aber Welpen will ich nun auch nicht gerade töten :-/

              Den ersten Parameter benutzt du als Array-Index in deinem JavaScript-Modell. Wenn diese Indizes nicht unmittelbar aufeinander folgen erzeugst du damit Löscher in deinem Array. Und Löschern muss man sich immer mit besonderer Aufmerksamkeit widmen, damit hast du ja schon Erfahrungen gemacht (length-Eigenschaft). Du kannst jetzt die Löscher bestehen lassen und Ausnahmenbehandlungen an allen Ecken und Enden hinzufügen, oder du passt deine Datenstruktur dahingehend an, dass sie keine Löscher mehr enthält.

              Dafür ist's zu spät. Dafür müsste ich jetzt zu viel umschreiben. Ich denke, ich habe die Löcher im Griff, jetzt wo ich erstmal weiß, dass sie da sind. Mir war irgendwie abhanden gekommen, dass beim manuellen Erstellen von Keys ja trotzdem "leere" Keys dazwischen sind.

              null steht überall da, wo dein Array eine Lücke hat.

              Toll, wie sich nach und nach alles lichtet. Also nich im Array, in meinem Kopf mein ich :-)

              Das heißt, du hast vor mit deinem JavaScript Daten an den Server zu übermitteln und du benutzt dazu JSON als Austauschformat. Das ist ne feine Sache, wenn du das noch weiterspinnst kommt dir vielleicht irgendwann der Gedanke, dass dein JavaScript sich die Daten auch schon im JSON-Format vom Server abholen kann. Damit kannst du den Hunde-Welpen-Killer wieder bändigen.

              Hm naja, die geholten Daten werden ja noch verändert. Ich hole mir die Daten aus der DB ab und speichere Sie im JavaScript-Array. Dieses Array wird dann durch den Benutzer über ein Formular verändert und die veränderten Daten und Berechnungen werden direkt im Browser angezeigt - ohne Serverkommunikation, alles über das Array. Erst beim Absenden schicke ich das Array mit den IDs der Spieler und den zugehörigen Spieldaten an ein PHP-Script.

              Jedenfalls funktioniert das Ganze jetzt erstmal, wie es soll. Jetzt kanns endlich weitergehen.

              Vielen Dank nochmal für die Hilfe.

              Onkel Schnitzel