Hat JavaScript eine eingebaute Stringbuilder-Klasse?

Antworten:

318

Wenn Sie Code für Internet Explorer schreiben müssen, stellen Sie sicher, dass Sie eine Implementierung ausgewählt haben, die Array-Joins verwendet. Das Verketten von Zeichenfolgen mit dem Operator +oder +=ist im IE extrem langsam. Dies gilt insbesondere für IE6. In modernen Browsern +=ist dies normalerweise genauso schnell wie Array-Joins.

Wenn ich viele String-Verkettungen durchführen muss, fülle ich normalerweise ein Array und verwende keine String-Builder-Klasse:

var html = [];
html.push(
  "<html>",
  "<body>",
  "bla bla bla",
  "</body>",
  "</html>"
);
return html.join("");

Beachten Sie, dass die pushMethoden mehrere Argumente akzeptieren.

Fabian Jakobs
quelle
7
Und wenn Sie eine Inline-Ausgabe generieren oder alle Mitglieder Literale sind, [foo(), "bar", "baz"].join("");funktioniert dies auch.
Anonym
1
Während man wahrscheinlich nicht erwarten kann, dass Dropbox-Links fast 3 Jahre lang funktionieren, wäre ich gespannt auf den Vergleich - und ob er noch hält.
Cornelius
1
@ DaveWard, Ihr Link ist kaputt :(
Ivan Kochurkin
Ich finde das viel besser lesbar als String + String + String
Andrew Ehrlich
12
Ich wusste nicht, dass ich pushmehrere Argumente akzeptieren kann. Die zufälligen Dinge, die du lernst.
Carcigenicate
55

Ich habe gerade die Leistung auf http://jsperf.com/javascript-concat-vs-join/2 überprüft . Die Testfälle verketten oder verbinden das Alphabet 1.000 Mal.

In aktuellen Browsern (FF, Opera, IE11, Chrome) ist "concat" etwa vier- bis zehnmal schneller als "join".

In IE8 geben beide ungefähr gleiche Ergebnisse zurück.

In IE7 ist "Join" leider etwa 100-mal schneller.

Andreas
quelle
3
Danke dafür. Dies sollte in der Antwortliste aufgeführt werden. Es ist auch auf IE10 viel schneller (ich weiß, dass dies kein moderner Browser ist, aber ich erwähne es für potenzielle NMCI-Entwickler, die dies sehen).
James Wilson
@Andreas Ich glaube, Ihr Test trifft in Chrome auf einen Codepfad, in dem die eigentliche Verkettung nie ausgeführt wird, da die Zeichenfolge nie gelesen wird. Selbst wenn dies erzwungen wird
Joseph Lennox
37

Nein, es gibt keine integrierte Unterstützung für das Erstellen von Zeichenfolgen. Sie müssen stattdessen die Verkettung verwenden.

Sie können natürlich ein Array aus verschiedenen Teilen Ihrer Zeichenfolge erstellen und join()dieses Array dann aufrufen. Dies hängt jedoch davon ab, wie der Join in dem von Ihnen verwendeten JavaScript-Interpreter implementiert ist.

Ich habe ein Experiment durchgeführt, um die Geschwindigkeit der str1+str2Methode mit der der Methode zu vergleichen array.push(str1, str2).join(). Der Code war einfach:

var iIterations =800000;
var d1 = (new Date()).valueOf();
str1 = "";
for (var i = 0; i<iIterations; i++)
    str1 = str1 + Math.random().toString();
var d2 = (new Date()).valueOf();
log("Time (strings): " + (d2-d1));

var d3 = (new Date()).valueOf();
arr1 = [];
for (var i = 0; i<iIterations; i++)
    arr1.push(Math.random().toString());
var str2 = arr1.join("");
var d4 = (new Date()).valueOf();
log("Time (arrays): " + (d4-d3));

Ich habe es in Internet Explorer 8 und Firefox 3.5.5 getestet, beide unter Windows 7 x64.

Am Anfang habe ich eine kleine Anzahl von Iterationen getestet (einige hundert, einige tausend Elemente). Die Ergebnisse waren unvorhersehbar (manchmal dauerte die Verkettung von Zeichenfolgen 0 Millisekunden, manchmal 16 Millisekunden, das gleiche gilt für das Verbinden von Arrays).

Als ich die Anzahl auf 50.000 erhöhte, waren die Ergebnisse in verschiedenen Browsern unterschiedlich - in Internet Explorer war die Verkettung von Zeichenfolgen schneller (94 Millisekunden) und die Verknüpfung langsamer (125 Millisekunden), während in Firefox die Array-Verknüpfung schneller war (113 Millisekunden) als String-Joining (117 Millisekunden).

Dann habe ich die Anzahl auf 500'000 erhöht. Nun ist die array.join()war langsamer als String - Verkettung in beiden Browsern: String - Verkettung war 937 ms in Internet Explorer, 1155 ms in Firefox, Array beitreten 1265 in Internet Explorer und 1207 ms in Firefox.

Die maximale Anzahl von Iterationen, die ich in Internet Explorer testen konnte, ohne dass "die Ausführung des Skripts zu lange dauert", betrug 850.000. Dann war Internet Explorer 1593 für die Verkettung von Zeichenfolgen und 2046 für die Array-Verknüpfung, und Firefox hatte 2101 für die Verkettung von Zeichenfolgen und 2249 für die Array-Verknüpfung.

Ergebnisse - Wenn die Anzahl der Iterationen gering ist, können Sie versuchen, sie zu verwenden array.join(), da sie in Firefox möglicherweise schneller sind. Wenn die Anzahl zunimmt, ist die string1+string2Methode schneller.

AKTUALISIEREN

Ich habe den Test mit Internet Explorer 6 (Windows XP) durchgeführt. Der Prozess wurde angehalten, um sofort zu reagieren, und endete nie, wenn ich den Test mit mehr als 100.000 Iterationen versuchte. Bei 40.000 Iterationen waren die Ergebnisse

Time (strings): 59175 ms
Time (arrays): 220 ms

Dies bedeutet: Wenn Sie Internet Explorer 6 unterstützen müssen, wählen Sie, array.join()was viel schneller als die Verkettung von Zeichenfolgen ist.

Naivisten
quelle
join()ist Teil von ECMAScript und wird von jedem JavaScript-Interpreter implementiert. Warum sollte es "abhängen"?
Eli Gray
er meinte, wie es implementiert wurde ... wenn es so implementiert ist, dass in einer Schleife die Zeichenfolge kontinuierlich angehängt wird und nicht auf einmal erstellt wird, dann wäre die Verwendung von join sinnlos
John
Ja, das habe ich eigentlich gemeint. Verzeihen Sie mein Englisch ;-) Ich habe Ergebnisse eines Vergleichs hinzugefügt, wie schnell welche Methode in zwei Browsern funktioniert. Sie können sehen, es ist anders.
Naivisten
2
IE6 ist wie immer die Ausnahme :)
Gordon Tucker
10
Leute mit IE6 sind es jedoch gewohnt, dass alles sehr langsam ist. Ich glaube nicht, dass sie dir die Schuld geben werden.
Lodewijk
8

Dieser Code sieht aus wie die Route, die Sie mit ein paar Änderungen einschlagen möchten.

Sie sollten die Append-Methode so ändern, dass sie so aussieht. Ich habe es geändert, um die Nummer 0 zu akzeptieren und es zurückgeben zu lassen, thisdamit Sie Ihre Anhänge verketten können.

StringBuilder.prototype.append = function (value) {
    if (value || value === 0) {
        this.strings.push(value);
    }
    return this;
}
Gordon Tucker
quelle
Warum nur Nicht-NaN-Zahlen und nicht leere Zeichenfolgen akzeptieren? Ihre Methode wird nicht akzeptieren null, false, leere Strings, undefinedoder NaN.
Eli Gray
@Elijah - Ich bevorzuge es, meine StringBuilder-Klasse sauber zu halten, indem ich nur gültige Zeichenfolgen und Zahlen akzeptiere. Es ist nur eine persönliche Präferenz.
Gordon Tucker
5

Die ECMAScript 6-Version (auch bekannt als ECMAScript 2015) von JavaScript führte String-Literale ein .

var classType = "stringbuilder";
var q = `Does JavaScript have a built-in ${classType} class?`;

Beachten Sie, dass Back-Ticks anstelle von einfachen Anführungszeichen die Zeichenfolge einschließen.

Theophilus
quelle
17
Wie beantwortet dies die Frage?
Peter Mortensen
@Peter Mortensen, diese Antwort bietet lediglich eine andere Möglichkeit, einen String zu erstellen. Im Originalposter wurde nicht angegeben, welche Art von String Builder-Funktionalität gesucht wurde.
Theophilus
1
Dies beantwortet die Frage nicht. Überhaupt.
Massimiliano Kraus
3

In C # können Sie so etwas tun

 String.Format("hello {0}, your age is {1}.",  "John",  29) 

In JavaScript könnten Sie so etwas tun

 var x = "hello {0}, your age is {1}";
 x = x.replace(/\{0\}/g, "John");
 x = x.replace(/\{1\}/g, 29);
Sport
quelle
2
Ich laufen sehr Zweifel einen regulären Ausdruck anstelle eines Strings kommen wird mehr performant
tic
Darüber hinaus ist dies eine schreckliche Implementierung. Es wird unterbrochen, wenn die Zeichenfolge, durch die {0}ersetzt wird, enthält {1}.
Ikegami
@ikegami Der String ist keine Variable, sondern eine Konstante. Sie wissen also, was a priori enthalten ist.
Sport
@sports, das Kopieren und Einfügen all dessen in Ihren Code ist eine noch schlechtere Idee.
Ikegami
Ein Liner mit $ 1 und $ 2 ersetzt die Nicht-Capture-Gruppen: x..replace (/ ([\ s \ S] *?) \ {0 \} ([\ s \ S] *?) \ {1 \} / g, "$ 1Tom $ 225")
T.CK
1

Für Interessenten gibt es hier eine Alternative zum Aufrufen von Array.join:

var arrayOfStrings = ['foo', 'bar'];
var result = String.concat.apply(null, arrayOfStrings);
console.log(result);

Die Ausgabe ist erwartungsgemäß die Zeichenfolge 'foobar'. In Firefox übertrifft dieser Ansatz Array.join, wird jedoch durch + Verkettung übertroffen. Da für String.concat jedes Segment als separates Argument angegeben werden muss, ist der Aufrufer durch die von der ausführenden JavaScript-Engine festgelegte Begrenzung der Argumentanzahl begrenzt. Weitere Informationen finden Sie in der Dokumentation zu Function.prototype.apply () .

Aaron
quelle
Dies schlägt in Chrome fehl, da "String.concat" undefiniert ist. Stattdessen können Sie '' .concat.apply ('', arrayOfStrings) verwenden. Dies ist jedoch immer noch eine sehr langsame Methode.
Andreas
1

Ich habe diese Funktion definiert:

function format() {
        var args = arguments;
        if (args.length <= 1) { 
            return args;
        }
        var result = args[0];
        for (var i = 1; i < args.length; i++) {
            result = result.replace(new RegExp("\\{" + (i - 1) + "\\}", "g"), args[i]);
        }
        return result;
    }

Und kann wie c # aufgerufen werden:

 var text = format("hello {0}, your age is {1}.",  "John",  29);

Ergebnis:

Hallo John, du bist 29 Jahre alt.

TotPeRo
quelle
1
Ich mag das ... sieht aus wie c #
Ayo Adesina
2
Diese Antwort hat nichts mit der Frage zu tun.
Massimiliano Kraus
0

Wenn ich in JavaScript viel String-Verkettung mache, suche ich nach Vorlagen. Handlebars.js funktioniert recht gut und hält HTML und JavaScript besser lesbar. http://handlebarsjs.com

Anfang
quelle