Felix Riesterer: String.concat funktioniert im Firefox 68 nicht mehr

Liebe Mitlesende,

hatte ein Uralt-Script von mir heute in den Händen, welches Strings nicht "addiert", sondern tatsächlich String.concat(a, b, c) stattdessen verwendet. Das gibt es in FF68 nicht mehr. Wenn man das unbedingt wollte, müsste man jetzt String.prototype.concat(a, b, c) verwenden - also lieber doch "addieren".

Liebe Grüße

Felix Riesterer

  1. Hallo Felix,

    hatte ein Uralt-Script von mir heute in den Händen, welches Strings nicht "addiert", sondern tatsächlich String.concat(a, b, c) stattdessen verwendet. Das gibt es in FF68 nicht mehr. Wenn man das unbedingt wollte, müsste man jetzt String.prototype.concat(a, b, c) verwenden - also lieber doch "addieren".

    String.prototype.concat solltest du nicht so wie oben beschrieben verwenden, sondern so, wie es gedacht ist:

    const a = 'Hallo';
    console.log(a.concat(' Felix', ', wie geht es dir?'))
    

    LG,
    CK

    1. Lieber Christian,

      sondern so, wie es gedacht ist:

      const a = 'Hallo';
      console.log(a.concat(' Felix', ', wie geht es dir?'))
      

      aha, "wie es gedacht ist"? Nun, warum nannten sie die Methode dann nicht append oder extend? Das Verb concatenate bedeutet "verketten". Damit wäre auch meine ursprüngliche Verwendung "gedacht".

      Man kann nur dazu raten, dass man Stringverkettungen in JS besser mit den +-Operator anstatt dieser Methode vornimmt.

      Liebe Grüße

      Felix Riesterer

      1. Hallo Felix,

        sondern so, wie es gedacht ist:

        const a = 'Hallo';
        console.log(a.concat(' Felix', ', wie geht es dir?'))
        

        aha, "wie es gedacht ist"?

        Alle Methoden in String.prototype sind dafür gedacht, direkt auf einem String-Objekt angewendet zu werden.

        Nun, warum nannten sie die Methode dann nicht append oder extend?

        Extend ist ein Schlüsselwort, das wäre eine schlechte Wahl. Ansonsten: das frag am besten das standards comitee. 😉

        Das Verb concatenate bedeutet "verketten". Damit wäre auch meine ursprüngliche Verwendung "gedacht".

        Als Methode im String-Objekt ja, als Methode in String.prototype nein.

        LG,
        CK

        1. Hallo Christian,

          Alle Methoden in String.prototype sind dafür gedacht, direkt auf einem String-Objekt angewendet zu werden.

          leider nicht alle. Replace wirkt nur auf den Rückgabewert.

          Gruß
          Jürgen

          1. Hallo JürgenB,

            Alle Methoden in String.prototype sind dafür gedacht, direkt auf einem String-Objekt angewendet zu werden.

            leider nicht alle. Replace wirkt nur auf den Rückgabewert.

            Bitte?

            "abc".replace(/a/, 'b');
            

            LG,
            CK

            1. Hallo Christian,

              Hallo JürgenB,

              Alle Methoden in String.prototype sind dafür gedacht, direkt auf einem String-Objekt angewendet zu werden.

              leider nicht alle. Replace wirkt nur auf den Rückgabewert.

              Bitte?

              "abc".replace(/a/, 'b');
              

              wenn du das in der Console eintippst, wird dir der Rückgabewert angezeigt.

              Versuch mal

              text = "abc";          // -> "abc"
              text.replace("a","b"); // -> "bbc"
              text                   // -> "abc"
              

              Getestet im FF 68.

              Gruß
              Jürgen

              1. Hallo JürgenB,

                wenn du das in der Console eintippst, wird dir der Rückgabewert angezeigt.

                Versuch mal

                text = "abc";          // -> "abc"
                text.replace("a","b"); // -> "bbc"
                text                   // -> "abc"
                

                Ich glaube, du hast mich missverstanden. Ich sagte, die String.prototype-Methoden sind dazu gedacht auf String-Objekte angewandt zu werden, also 'abc'.replace('a', 'b') statt String.replace('abc', 'a', 'b') – ich sagte nicht, dass String.prototype-Methoden destruktiv sind.

                String-Objekte in JS sind immutable, keine der String.prototype-Methoden ist destruktiv, sie geben alle einen neuen String zurück.

                LG,
                CK

                1. Hallo Christian,

                  Ich glaube, du hast mich missverstanden. …

                  so isses.

                  String-Objekte in JS sind immutable, keine der String.prototype-Methoden ist destruktiv, sie geben alle einen neuen String zurück.

                  leider. Ich habe daher heute morgen im Bus ein replace gebastelt, das direkt im String durchgeführt wird. Da bei mir die Anzahl der Ersetzungen proportional zur Stringlänge ist, musste ich einen String mit 150*n Bytes n-mal umkopieren, also Ordnung n². Jetzt habe ich Ordnung n.

                  Gruß
                  Jürgen

      2. Hallo Felix,

        extend oder append vs concat

        Nein, die Namen sind schlecht. a.extend("b") oder a.append(y) suggeriert, dass a modifziert wird. Methoden dieses Namens und mit dieser Semantik gibt es an etlichen Stellen (DOM, jQuery). Strings sind in JS aber unveränderlich (immutable).

        Man kann nur dazu raten, dass man Stringverkettungen in JS besser mit den +-Operator anstatt dieser Methode vornimmt.

        Als universeller Rat ist das nicht zu empfehlen, beides hat seinen Sinn. Und die concat-Methode auf dem Prototypen ist im ECMA Standard und dürfte daher zukunftssicher sein.

        Ein binärer Operator verknüpft zwei Objekte und liefert ein neues. Wenn ich eine Folge von Verkettungen habe: "Hallo " + name + ", du bist " + alter + " Jahre alt", werden auf diese Weise 3 Zwischenobjekte erzeugt, d.h. auf dem Heap übereinander gestapelt und wieder verworfen. Nur das letzte bleibt übrig und darunter ein Loch, das der Garbage Collector flicken muss.

        Die concat-Methode kann die Längen aller Segmente vorab bestimmen, einen neuen Stringbuffer der benötigten Länge allocieren und die Segmentinhalte dort zusammenfügen. Das ist schneller und belastet den Heap weniger.

        Ob es performanter ist, für mein Beispiel oben einen Template String zu verwenden, müsste man messen. Ist aber Mikrooptimierung und im Normalfall wurscht.

        Ob die JS Engines der heutigen Browser im Stande sind, eine Folge von + Operationen auf Strings beim JIT Compile zu erkennen und in ein concat umzuwandeln, müsste man ebenfalls eruieren. Diese Optimierung gibt's beispielsweise in C#.

        Rolf

        --
        sumpsi - posui - clusi
        1. Hallo Rolf,

          Ob die JS Engines der heutigen Browser im Stande sind, eine Folge von + Operationen auf Strings beim JIT Compile zu erkennen und in ein concat umzuwandeln, müsste man ebenfalls eruieren. Diese Optimierung gibt's beispielsweise in C#.

          Hättest du diesen Teilsatz nicht angefügt, hätte ich dir heftigst widersprechen müssen 😉 denn Benchmarks zeigen, dass + und += schneller sind als concat – und auch als [].join(), und das in allen JS-Engines bis runter auf IE. Da ist eine Menge Optimierungsaufwand betrieben worden.

          LG,
          CK

        2. @@Rolf B

          Ein binärer Operator verknüpft zwei Objekte und liefert ein neues. Wenn ich eine Folge von Verkettungen habe: "Hallo " + name + ", du bist " + alter + " Jahre alt", werden auf diese Weise 3 Zwischenobjekte erzeugt, d.h. auf dem Heap übereinander gestapelt und wieder verworfen. Nur das letzte bleibt übrig und darunter ein Loch, das der Garbage Collector flicken muss.

          `Hallo ${name}, du bist ${alter} Jahre alt` 
          

          dürfte diesbezüglich besser sein, oder?

          Außerdem ist es besser lesbar, IMHO.

          (Wenn’s auch in Uralt-Browsern laufen soll, muss man das freilich durch einen Transpiler laufen lassen.)

          LLAP 🖖

          --
          „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
  2. Hallo Felix,

    ja. Die waren eine Erweiterung des Fuchses (bzw. des Spinnenaffen), die es nicht nach ECMA geschafft hat.

    Sie wurden im FF53 missbilligt, aber die Füchse haben es im FF68 nicht für nötig befunden, den Übergang von deprecated zu removed aufzuschreiben. Man findet es indirekt hier, und hier.

    Niemand hindert Dich, einen retro-Polyfill zu bauen, falls das für deine Zwecke einfacher ist 😉

    Rolf

    --
    sumpsi - posui - clusi