Verwendet Javascript unveränderliche oder veränderbare Zeichenfolgen? Benötige ich einen "String Builder"?
Verwendet Javascript unveränderliche oder veränderbare Zeichenfolgen? Benötige ich einen "String Builder"?
Antworten:
Sie sind unveränderlich. Sie können ein Zeichen innerhalb einer Zeichenfolge nicht mit so etwas wie ändern var myString = "abbdef"; myString[2] = 'c'
. Die String - Manipulationsmethoden wie trim
, slice
zurückkehren neue Saiten.
Wenn Sie zwei Verweise auf dieselbe Zeichenfolge haben, wirkt sich das Ändern einer auf die andere nicht aus
let a = b = "hello";
a = a + " world";
// b is not affected
Ich habe jedoch immer gehört, was Ash in seiner Antwort erwähnt hat (dass die Verwendung von Array.join für die Verkettung schneller ist), daher wollte ich die verschiedenen Methoden zum Verketten von Zeichenfolgen und zum Abstrahieren des schnellsten Wegs in einen StringBuilder testen. Ich habe einige Tests geschrieben, um zu sehen, ob dies wahr ist (ist es nicht!).
Dies war meiner Meinung nach der schnellste Weg, obwohl ich immer wieder dachte, dass das Hinzufügen eines Methodenaufrufs ihn langsamer machen könnte ...
function StringBuilder() {
this._array = [];
this._index = 0;
}
StringBuilder.prototype.append = function (str) {
this._array[this._index] = str;
this._index++;
}
StringBuilder.prototype.toString = function () {
return this._array.join('');
}
Hier sind Leistungsgeschwindigkeitstests. Alle drei bilden eine gigantische Zeichenfolge, die aus der "Hello diggity dog"
hunderttausendfachen Verkettung zu einer leeren Zeichenfolge besteht.
Ich habe drei Arten von Tests erstellt
Array.push
undArray.join
Array.push
, und Verwenden vonArray.join
Dann habe ich die gleichen drei Tests , die von ihnen in abstrahiert StringBuilderConcat
, StringBuilderArrayPush
und StringBuilderArrayIndex
http://jsperf.com/string-concat-without-sringbuilder/5 Bitte gehen Sie dort und laufen Tests , so dass wir eine schöne Probe erhalten. Beachten Sie, dass ich einen kleinen Fehler behoben habe, sodass die Daten für die Tests gelöscht wurden. Ich werde die Tabelle aktualisieren, sobald genügend Leistungsdaten vorhanden sind. Gehen Sie zu http://jsperf.com/string-concat-without-sringbuilder/5Die alte Datentabelle finden .
Hier sind einige Zahlen (letztes Update in Ma5rch 2018), wenn Sie dem Link nicht folgen möchten. Die Zahl bei jedem Test ist in 1000 Operationen / Sekunde ( höher ist besser )
| Browser | Index | Push | Concat | SBIndex | SBPush | SBConcat |
---------------------------------------------------------------------------
| Chrome 71.0.3578 | 988 | 1006 | 2902 | 963 | 1008 | 2902 |
| Firefox 65 | 1979 | 1902 | 2197 | 1917 | 1873 | 1953 |
| Edge | 593 | 373 | 952 | 361 | 415 | 444 |
| Exploder 11 | 655 | 532 | 761 | 537 | 567 | 387 |
| Opera 58.0.3135 | 1135 | 1200 | 4357 | 1137 | 1188 | 4294 |
Ergebnisse
Heutzutage handhaben alle immergrünen Browser die Verkettung von Zeichenfolgen gut. Array.join
hilft nur IE 11
Insgesamt ist Opera am schnellsten, viermal so schnell wie Array.join
Firefox ist an zweiter Stelle und Array.join
in FF nur geringfügig langsamer, in Chrome jedoch erheblich langsamer (3x).
Chrome ist an dritter Stelle, aber String Concat ist dreimal schneller als Array.join
Das Erstellen eines StringBuilder scheint die Leistung nicht zu stark zu beeinträchtigen.
Hoffe, jemand anderes findet das nützlich
Unterschiedlicher Testfall
Da @RoyTinker meinte, mein Test sei fehlerhaft, habe ich einen neuen Fall erstellt, bei dem keine große Zeichenfolge durch Verketten derselben Zeichenfolge erstellt wird. Für jede Iteration wird ein anderes Zeichen verwendet. Die Verkettung von Zeichenfolgen schien immer noch schneller oder genauso schnell zu sein. Lassen Sie uns diese Tests zum Laufen bringen.
Ich schlage vor, dass jeder über andere Möglichkeiten nachdenken sollte, um dies zu testen, und neue Links zu verschiedenen Testfällen hinzufügen kann.
join
Verkettung und String-Verkettung zu beschränken und so das Array vor dem Test zu erstellen . Ich denke nicht, dass das Betrug ist, wenn dieses Ziel verstanden wird (und join
das Array intern auflistet, so dass es auch kein Betrug ist, eine for
Schleife aus dem join
Test wegzulassen ).
Array.join
aus dem Nashornbuch :
In JavaScript sind Zeichenfolgen unveränderliche Objekte. Dies bedeutet, dass die darin enthaltenen Zeichen möglicherweise nicht geändert werden und dass Operationen an Zeichenfolgen tatsächlich neue Zeichenfolgen erstellen. Zeichenfolgen werden nach Referenz und nicht nach Wert zugewiesen. Wenn ein Objekt durch Referenz zugewiesen wird, ist im Allgemeinen eine Änderung, die durch eine Referenz am Objekt vorgenommen wurde, durch alle anderen Referenzen auf das Objekt sichtbar. Da Zeichenfolgen jedoch nicht geändert werden können, können Sie mehrere Verweise auf ein Zeichenfolgenobjekt haben und müssen sich keine Sorgen machen, dass sich der Zeichenfolgenwert ändert, ohne dass Sie es wissen
null
undefined
number
und einer der wenigen 5 Werttypen boolean
. Zeichenfolgen werden nach Wert und nicht nach Referenz zugewiesen und als solche übergeben. Strings sind also nicht nur unveränderlich, sie sind ein Wert . Die Zeichenfolge ändern "hello"
zu sein "world"
ist wie die von nun an die Nummer 3 der Entscheidung ist die Nummer 4 ... es macht keinen Sinn.
var a = "hello";var b=a;a.x=5;console.log(a.x,b.x);
String
mit dem Zeichenfolgenkonstruktor erstellte Objekte sind Wrapper um JavaScript-Zeichenfolgenwerte. Mit der .valueOf()
Funktion können Sie auf den Zeichenfolgenwert des Box-Typs zugreifen. Dies gilt auch für Number
Objekte und Zahlenwerte. Es ist wichtig zu beachten, dass String
Objekte, die mit erstellt wurden, new String
keine tatsächlichen Zeichenfolgen sind, sondern Wrapper oder Kästchen um Zeichenfolgen. Siehe es5.github.io/#x15.5.2.1 . Informationen
Leistungstipp:
Wenn Sie große Zeichenfolgen verketten müssen, fügen Sie die Zeichenfolgenteile in ein Array ein und verwenden Sie die Array.Join()
Methode, um die Gesamtzeichenfolge abzurufen. Dies kann für die Verkettung einer großen Anzahl von Zeichenfolgen um ein Vielfaches schneller sein.
StringBuilder
In JavaScript gibt es keine .
Nur um für einfache Köpfe wie meine (von MDN ) zu klären :
Unveränderliche Objekte sind Objekte, deren Status nach dem Erstellen des Objekts nicht mehr geändert werden kann.
Zeichenfolge und Zahlen sind unveränderlich.
Unveränderlich bedeutet:
Sie können einen Variablennamen auf einen neuen Wert verweisen lassen, der vorherige Wert wird jedoch weiterhin gespeichert. Daher die Notwendigkeit der Müllabfuhr.
var immutableString = "Hello";
// Im obigen Code wird ein neues Objekt mit einem Zeichenfolgenwert erstellt.
immutableString = immutableString + "World";
// Wir hängen jetzt "World" an den vorhandenen Wert an.
Es sieht so aus, als würden wir den String 'immutableString' mutieren, aber das sind wir nicht. Stattdessen:
Beim Anhängen des "immutableString" an einen Zeichenfolgenwert treten folgende Ereignisse auf:
- Der vorhandene Wert von "immutableString" wird abgerufen
- "World" wird an den vorhandenen Wert von "immutableString" angehängt.
- Der resultierende Wert wird dann einem neuen Speicherblock zugewiesen
- Das Objekt "immutableString" zeigt jetzt auf den neu erstellten Speicherplatz
- Zuvor erstellter Speicherplatz ist jetzt für die Speicherbereinigung verfügbar.
Der Wert für den Zeichenfolgentyp ist unveränderlich, aber das Zeichenfolgenobjekt , das mit dem Konstruktor String () erstellt wird, kann geändert werden, da es sich um ein Objekt handelt und Sie ihm neue Eigenschaften hinzufügen können.
> var str = new String("test")
undefined
> str
[String: 'test']
> str.newProp = "some value"
'some value'
> str
{ [String: 'test'] newProp: 'some value' }
Obwohl Sie neue Eigenschaften hinzufügen können, können Sie die bereits vorhandenen Eigenschaften nicht ändern
Ein Screenshot eines Tests in der Chrome-Konsole
Zusammenfassend ist 1. der gesamte Wert des Zeichenfolgentyps (primitiver Typ) unveränderlich. 2. Das String-Objekt ist veränderbar, aber der darin enthaltene String-Typ-Wert (primitiver Typ) ist unveränderlich.
new String
erzeugt einen veränderlichen Wrapper um einen unveränderlichen String
String
Objekt (Wrapper) vollständig neue Eigenschaften hinzufügen , was bedeutet, dass es nicht unveränderlich ist (standardmäßig; wie jedes andere Objekt, das Sie aufrufen Object.freeze
können, um es unveränderlich zu machen). Ein primitiver Zeichenfolgenwerttyp, unabhängig davon, ob er in einem String
Objektwrapper enthalten ist oder nicht, ist immer unveränderlich.
In Bezug auf Ihre Frage (in Ihrem Kommentar zu Ashs Antwort) zum StringBuilder in ASP.NET Ajax scheinen sich die Experten in dieser Frage nicht einig zu sein.
Christian Wenz sagt in seinem Buch Programming ASP.NET AJAX (O'Reilly), dass "dieser Ansatz keine messbaren Auswirkungen auf das Gedächtnis hat (tatsächlich scheint die Implementierung ein Tick langsamer zu sein als der Standardansatz)."
Auf der anderen Seite sagen Gallo et al. In ihrem Buch ASP.NET AJAX in Action (Manning): "Wenn die Anzahl der zu verkettenden Zeichenfolgen größer ist, wird der Zeichenfolgengenerator zu einem wesentlichen Objekt, um enorme Leistungseinbußen zu vermeiden."
Ich denke, Sie müssten Ihr eigenes Benchmarking durchführen, und die Ergebnisse können auch zwischen den Browsern unterschiedlich sein. Selbst wenn es die Leistung nicht verbessert, kann es dennoch als "nützlich" für Programmierer angesehen werden, die es gewohnt sind, mit StringBuilders in Sprachen wie C # oder Java zu codieren.
Es ist ein später Beitrag, aber ich habe unter den Antworten kein gutes Buchzitat gefunden.
Hier ist eine eindeutige Ausnahme von einem zuverlässigen Buch:
Zeichenfolgen sind in ECMAScript unveränderlich, was bedeutet, dass sich ihre Werte nach ihrer Erstellung nicht ändern können. Um die von einer Variablen gehaltene Zeichenfolge zu ändern, muss die ursprüngliche Zeichenfolge zerstört und die Variable mit einer anderen Zeichenfolge gefüllt werden, die einen neuen Wert enthält ... - Professionelles JavaScript für Webentwickler, 3. Ausgabe, S. 43
Die Antwort, die den Auszug aus dem Rhino-Buch zitiert, ist richtig in Bezug auf die Unveränderlichkeit von Zeichenfolgen, aber falsch: "Zeichenfolgen werden durch Referenz und nicht durch Wert zugewiesen." (wahrscheinlich wollten sie die Wörter ursprünglich anders ausdrücken).
Das Missverständnis "Referenz / Wert" wird im Kapitel "Professionelles JavaScript" im Kapitel "Primitive und Referenzwerte" erläutert:
Die fünf primitiven Typen ... [sind]: Undefiniert, Null, Boolesch, Zahl und Zeichenfolge. Auf diese Variablen wird als Wert zugegriffen, da Sie den in der Variablen gespeicherten tatsächlichen Wert bearbeiten. - Professionelles JavaScript für Webentwickler, 3. Aufl., S. 85
das ist gegen Objekte :
Wenn Sie ein Objekt bearbeiten, arbeiten Sie wirklich an einem Verweis auf dieses Objekt und nicht auf das eigentliche Objekt. Aus diesem Grund soll auf solche Werte als Referenz zugegriffen werden. - Professionelles JavaScript für Webentwickler, 3. Aufl., S. 85
JavaScript-Zeichenfolgen sind in der Tat unveränderlich.
Zeichenfolgen in Javascript sind unveränderlich