Christian S: Verhalten bei Füllen von leerem Array

Mahlzeit,

Ich möchte ein Array mit einer vorgegebenen Anzahl an Indices (je nachdem, wie viele Elemente einer gewissen Klasse ich im DOM habe) kreieren und diese dann füllen. Dabei bin ich auf ein Verhalten von Javascript gestoßen, das für mich keinen Sinn ergibt...

Und zwar lässt sich das Array nur füllen, wenn ich es zusätzlich in ein weiteres Array spreade. Warum?

let zuFuellendeAnzahl = 3; // eigentlich *classes*.length, hier der Einfachheit halber 3.

let arr1 = new Array(zuFuellendeAnzahl);
arr1.forEach((leer, index) => {
	arr1[index] = "Werte für Arr1";
});
console.log("arr1: ", arr1); // 👎 // WARUM arr1: [EMPTY x 3] ?

let arr2 = [...arr1];
arr2.forEach((leer, index) => {
	arr2[index] = "Werte für Arr2";
});
console.log("arr2: ", arr2); // 👍 // arr2: ["Werte für Arr2", "Werte für Arr2", "Werte für Arr2"]

var arr3 = Array.apply(null, Array(zuFuellendeAnzahl));
arr3.forEach(function(el, index) {
    arr3[index] = "Werte für Arr3";
});
console.log("arr2: ", arr3); // 👍 // arr3: ["Werte für Arr3", "Werte für Arr3", "Werte für Arr3"]

Feinste Grüße, Christian.

  1. @@Christian S

    let zuFuellendeAnzahl = 3; // eigentlich *classes*.length, hier der Einfachheit halber 3.
    
    let arr1 = new Array(zuFuellendeAnzahl);
    

    Beide Male wäre const angebracht, nicht let.

    Zum Füllen eines Array gibt es eine entsprechende Methode.

    Das ist, was du willst?

    const zuFuellendeAnzahl = 3;
    
    const arr1 = new Array(zuFuellendeAnzahl);
    arr1.fill("Werte für Arr1");
    
    console.log(arr1); // ["Werte für Arr1", "Werte für Arr1", "Werte für Arr1"]
    

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

    --
    Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
    1. Lieber Gunnar,

      Zum Füllen eines Array gibt es eine entsprechende Methode.

      die gibt es auch hier im Wiki (Array.fill()). Ich sähe es lieber, wenn Du dorthin verlinktest.

      Liebe Grüße

      Felix Riesterer

  2. Hallo Christian,

    führe dies hier mal in der Browserconsole aus (let/const/var ist da wurscht):

    new Array(3).forEach( (val, i) => console.log(i, val) );
    [5,6,7].forEach( (val, i) => console.log(i, val) );
    

    WTF? Ein Array-Element kann gefüllt oder leer sein. Leer ist was anderes als NaN oder undefined. new Array(n) erzeugt n leere Einträge. forEach überspringt leere Einträge. Darum gibt die erste Zeile nichts aus.

    D.h. in deinem ersten Versuch wird der Callback nullmal aufgerufen.

    Ein Spread kopiert das Array und erzeugt pro Eintrag Werte. Auch für die leeren.

    a = [];
    a[4] = 7;
    console.log(a);        // empty x 4, 7
    console.log([... a]);  // undefined, undefined, undefined, undefined, 7
    

    Deswegen klappt's nach dem Spread.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Dank euch recht schön!

      Ein Spread kopiert das Array und erzeugt pro Eintrag Werte. Auch für die leeren.

      (...)

      Rolf

      Heißt also zusammenfassend (nur um sicherzugehen, dass ich das auch richtig verstanden habe):

      
      new Array(3); // erzeugt: [,,]
      [...new Array(3)] // SPREAD "zwingt" Werte in das Array, erzeugt also [undefined, undefined, undefined]
      

      ?

      Danke!

      1. Hallo Christian,

        new Array(3); // erzeugt: [,,]

        Keine Ahnung wie man sowas korrekt darstellt, aber ja, so ist es.

        Arrays und Objekte sind ja letztlich zwei Sichten auf das gleiche Ding. Fasst man das Array als Objekt auf, dann erzeugt new Array(3) ein Objekt mit Array-Prototyp und einem einzigen Property: length. Dieses Property ist nicht enumerable, d.h. eine for...in Schleife beachtet es nicht.

        [... new Array(3)] macht einen Spread davon, das Ergebnis ist ein Objekt mit Array-Prototyp und vier Properties. length: 3, 0: undefined, 1: undefined, 2: undefined.

        Ein Blick auf die Chrome-Konsole macht es vielleicht auch nochmal klarer:

        Da steht proto: Object, aber das heißt nicht, dass der Prototyp dieser Array-Objekte das Object` Objekt ist. Sondern dass der Prototyp ein Objekt ist. Und zwar das Prototyp-Objekt des Array-Konstruktors.

        Object.getPrototypeOf([...new Array(3)]) == Array.prototype
        

        meldet true. Prototypen sind die JavaScript-Methode, um Objektklassen zu bilden. Unser Wiki kann was davon erzählen.

        Rolf

        --
        sumpsi - posui - obstruxi