Martl: String in Zahl umwandeln

Hallo Forum,

ich möchte eine String, der Ziffern enthält zur weiteren Verarbeitung in eine Zahl umwandeln; funktioniert soweit auch. Auf dem Weg dorthin ist mir aber etwas aufgefallen, das ich nicht verstehe:

Ein Element enthält beispielsweise einen Zeilenumbruch und die Ziffer 8.


string = element.innerHTML; //Ergebnis: \n8

Number(string) - 1; //Ergebnis: NaN - logisch

Number(string) + 1; //Ergebnis: NaN - auch logisch

string.valueOf() - 1; //Ergebnis: 7 - scheint ok?

string.valueOf() + 1; //Ergebnis: 81 - und das verstehe ich nicht!

Könnte mir jemand erklären, warum hier die Subtraktion scheinbar korrekt ausgeführt wird, die Addition aber nicht?

Grüße, Martl

(Wenn Plan A nicht funktioniert: Keine Panik, das Alphabet hat noch weitere 25 Buchstaben)

  1. Hallo

    Könnte mir jemand erklären, warum hier die Subtraktion scheinbar korrekt ausgeführt wird, die Addition aber nicht?

    Weil der Plusoperator nicht nur für die Addition verwendet wird, sondern auch zur Konkatenation von Strings. Das heißt, wenn einer der beiden Werte vor oder nach dem Plus ein String ist, dann wird der andere Wert ebenfalls in einen String konvertiert und die beiden Zeichenketten werden verknüpft.

    const a = '4', b = 3;
    
    console.log(typeof (a - b)); // number (1)
    
    console.log(typeof (a + b)); // string (43)
    
    console.log(typeof (b + a)); // string (34)
    

    Beim Minusoperator findet eine solche implizite Typkonvertierung nicht statt, da er keine zusätzliche Bedeutung wie der Plusoperator bestitzt. Seine Aufgabe ist nur die Subtraktion.

    Viele Grüße,

    Orlok

    1. Tach!

      Könnte mir jemand erklären, warum hier die Subtraktion scheinbar korrekt ausgeführt wird, die Addition aber nicht?

      Weil der Plusoperator nicht nur für die Addition verwendet wird, sondern auch zur Konkatenation von Strings.

      Soweit der eine Teil. Aber warum schafft es der Minus-Operator (oder auch parseInt()), den Wert \n8 in eine Zahl umzuwandeln, der Konstruktor von Number aber nicht?

      P.S. die valueOf()-Aufrufe im OP sind nutzlos. innerHTML liefert einen primitiven String und kein String-Objekt. valueOf() liefert auch nur einen primitiven String. Da findet also keine sichtbare Aktion statt.

      dedlfix.

      1. Hallo dedlfix

        Soweit der eine Teil. Aber warum schafft es der Minus-Operator (oder auch parseInt()), den Wert \n8 in eine Zahl umzuwandeln, der Konstruktor von Number aber nicht?

        Wie kommst du darauf, dass der Konstruktor von Number das nicht schaffen sollte? Ich meine, vorausgesetzt, man ruft ihn als Funktion und nicht als Konstruktor auf …

        console.log(typeof Number('\n8')); // number
        

        Bei der Auswertung eines Ausdrucks mit dem Minusoperator wird für die Werte links und rechts des Operators die abstrakte Operation ToNumber performt, welche einen String in einen Wert vom Typ Number konvertiert und dabei Whitespace ignoriert. Die gleiche Operation wird auch von parseInt durchgeführt.

        Bei einem Aufruf von Number wird ebenfalls ToNumber auf den als Argument übergebenen Wert angewandt, wobei dann das Aufrufmuster darüber entscheidet, ob der von dieser Operation zurückgegebene Wert auch der Rückgabewert von Number ist, oder ob ein Objekt zurückgegeben werden soll, welches diesen primitiven Wert in einer internen Eigenschaft kapselt.

        const value = '\n8';
        
        console.log(value - 3); // 5
        
        [parseInt, Number].forEach(fn =>
          console.log(typeof fn(value))  // number, number
        );
        

        In allen drei Fällen wird also dieselbe Operation ausgeführt und dementsprechend findet auch in allen drei Fällen eine Typkonvertierung von String zu Number statt.

        Viele Grüße,

        Orlok

        1. Hallo,

          In allen drei Fällen wird also dieselbe Operation ausgeführt und dementsprechend findet auch in allen drei Fällen eine Typkonvertierung von String zu Number statt.

          Und welche von diesen drei Fällen sind die beiden von Martl, bei denen NaN rauskommt?

          Gruß
          Kalk

          1. Hallo Kalk

            Und welche von diesen drei Fällen sind die beiden von Martl, bei denen NaN rauskommt?

            Ich zitiere mal aus seinem Posting:

            Ein Element enthält beispielsweise einen Zeilenumbruch und die Ziffer 8.

            Mit Zeilenumbruch meinte er wohl eigentlich ein BR-Element, sodass beim Aufruf von innerHTML auf dem referenzierten Element in etwa folgendes zurückgegeben worden ist.

            console.log(element.innerHTML); // <br> 8
            

            Wenn man diesen String an ToNumber übergibt, auf welche Weise auch immer, dann wird daraus NaN, was dann natürlich auch das Ergebnis der Subtraktion ist.

            <body>
              <p>
               8
              </p>
              <p><br>8</p>
              <script>
            
                const p1 = document.body.firstElementChild;
                console.log(Number(p1.innerHTML)); // 8
            
                const p2 = p1.nextSibling;
                console.log(Number(p2.innerHTML)); // NaN
            
              </script>
            </body>
            

            Viele Grüße,

            Orlok

            1. Hallo Orlok,

              Ich zitiere mal aus seinem Posting:

              Ich auch.

              Ein Element enthält beispielsweise einen Zeilenumbruch und die Ziffer 8.

              Mit Zeilenumbruch meinte er wohl eigentlich ein BR-Element, sodass beim Aufruf von innerHTML auf dem referenzierten Element in etwa folgendes zurückgegeben worden ist.

              console.log(element.innerHTML); // <br> 8
              

              Nö. Er schreibt

              string = element.innerHTML; //Ergebnis: \n8
              

              meint also \n.

              Bis demnächst
              Matthias

              --
              Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
            2. Tach!

              Ein Element enthält beispielsweise einen Zeilenumbruch und die Ziffer 8.

              Mit Zeilenumbruch meinte er wohl eigentlich ein BR-Element, sodass beim Aufruf von innerHTML auf dem referenzierten Element in etwa folgendes zurückgegeben worden ist.

              console.log(element.innerHTML); // <br> 8
              

              Unwahrscheinlich, denn "<br>8" - 1 ergibt nicht 7, auch nicht mit valueOf().

              dedlfix.

          2. Hallo Tabellenkalk,

            Und welche von diesen drei Fällen sind die beiden von Martl, bei denen NaN rauskommt?

            mir ist da ein blöder Fehler unterlaufen:

            "Vorspanntext" + Number(string) + 1 //Ergebnis: NaN
            
            "Vorspanntext" + (Number(string) + 1) //Ergebnis: 9
            
            

            Tut mir leid wegen der Verwirrung. Aber trotzdem war der Diskurs für mich recht lehrreich. Nochmal meinen Dank an alle Beteiligten.

            Grüße, Martl

            (Ich hab' jetzt wieder Plan)

        2. Tach!

          Wie kommst du darauf, dass der Konstruktor von Number das nicht schaffen sollte? Ich meine, vorausgesetzt, man ruft ihn als Funktion und nicht als Konstruktor auf …

          Weil es im OP anscheinend so war. Number("\n8")-1 liefert dort laut Kommentar ein NaN. Das konnte ich vorhin auch irgendwie nachvollziehen und hatte da ein new verwendet, ohne bemerkt zu haben, dass das im OP fehlte. Aber selbst mit dem new bekomme ich es nun nicht mehr hin. Mit und ohne new ergibt es 7 und nicht NaN.

          Ah, vermutlich folgen auf die 8 noch Nicht-Whitespace-Zeichen. Dann klappt zwar parseInt(), aber Number() nicht mehr, egal ob mit oder ohne new. (Aber ich hab doch bei meinem ersten Versuch keine zusätzlichen Zeichen angehängt. Na, wer weiß.)

          dedlfix.

    2. Hallo Orlok,

      ebenfalls in einen String konvertiert...

      das war mir bisher entgangen. Danke!

      Grüße, Martl

      (Wenn Plan A nicht funktioniert: Keine Panik, das Alphabet hat noch weitere 25 Buchstaben)