`String`-Objekt

In diesem Artikel wird das String-Objekt erklärt.

Die Erklärung umfasst alles von den Grundlagen bis zu fortgeschrittenen Techniken, einschließlich Fallstricke im Zusammenhang mit Unicode und regulären Ausdrücken, Schritt für Schritt und leicht verständlich.

YouTube Video

String-Objekt

Strings gehören in JavaScript zu den am häufigsten verwendeten Typen in der täglichen Entwicklung.

Unterschied zwischen primitiven Strings und String-Objekten

Primitive Strings (wie "hello") verhalten sich anders als Wrapper-Objekte wie new String("hello"). In der Regel sollten Sie primitive Strings verwenden; die Objektform ist kaum erforderlich.

1// Primitive string
2const a = "hello";
3
4// String wrapper object
5const b = new String("hello");
6
7console.log(typeof a); // "string"
8console.log(typeof b); // "object"
9console.log(a === b);  // false — wrapper objects are not strictly equal
  • Dieser Code zeigt den Typunterschied zwischen einem primitiven String und einem Wrapper sowie ihr Verhalten bei striktem Vergleich. Vermeiden Sie in den meisten Fällen die Verwendung von new String() und verwenden Sie stattdessen primitive Strings.

Möglichkeiten zur Erstellung von Strings (Literale und Template-Literale)

Template-Literale eignen sich gut zum Einbetten von Variablen und für mehrzeilige Strings. Sie können Variablen intuitiv einfügen und Ausdrücke auswerten.

1const name = "Alice";
2const age = 30;
3
4// Template literal
5const greeting = `Name: ${name}, Age: ${age + 1}`;
6
7console.log(greeting); // "Name: Alice, Age: 31"
  • Template-Literale sind sehr gut lesbar und ideal für den Aufbau komplexer, auch mehrzeiliger Strings.

Häufige Methoden (Suche und Extraktion von Teilstrings)

Das String-Objekt bietet viele grundlegende Methoden.

 1const text = "Hello, world! Hello again.";
 2
 3// search
 4console.log(text.indexOf("Hello"));       // 0
 5console.log(text.indexOf("Hello", 1));    // 13
 6console.log(text.includes("world"));      // true
 7console.log(text.startsWith("Hello"));    // true
 8console.log(text.endsWith("again."));     // true
 9
10// slice / substring
11console.log(text.slice(7, 12));           // "world"
12console.log(text.substring(7, 12));       // "world"
  • slice und substring sind ähnlich, behandeln aber negative Indizes unterschiedlich. slice interpretiert negative Werte als Positionen vom Ende her. Seien Sie sich darüber im Klaren, welche Methode Sie verwenden.

Aufteilen und Zusammenfügen (split / join)

Es ist üblich, einen String zum Verarbeiten in ein Array aufzuteilen und anschließend wieder zusammenzufügen.

1const csv = "red,green,blue";
2const arr = csv.split(","); // ["red","green","blue"]
3
4console.log(arr);
5console.log(arr.join(" | ")); // "red | green | blue"
  • Ein gängiges Muster ist, mit split einen String aufzuteilen, das Array mit map oder filter zu verarbeiten und anschließend mit join wieder zusammenzufügen.

Ersetzen und reguläre Ausdrücke

replace ersetzt nur das erste Vorkommen. Um alle Vorkommen zu ersetzen, verwenden Sie das g-Flag in einem regulären Ausdruck. Durch Übergeben einer Funktion als Ersatz können Sie auch dynamische Ersetzungen durchführen.

 1const s = "foo 1 foo 2";
 2
 3// replace first only
 4console.log(s.replace("foo", "bar")); // "bar 1 foo 2"
 5
 6// replace all using regex
 7console.log(s.replace(/foo/g, "bar")); // "bar 1 bar 2"
 8
 9// replace with function
10const r = s.replace(/\d+/g, (match) => String(Number(match) * 10));
11console.log(r);    // "foo 10 foo 20"
  • Mit der dynamischen Ersetzung per Funktion können Sie prägnanten Code schreiben, der Treffer analysiert und transformiert.

Groß-/Kleinschreibung und Normalisierung

Für mehrsprachige Unterstützung und Vergleiche ist neben toLowerCase und toUpperCase auch die Unicode-Normalisierung (normalize) wichtig. Dies ist besonders beim Vergleich von Zeichen mit Akzent erforderlich.

 1// Case conversion example:
 2// "\u00DF" represents the German letter "ß".
 3// In some locales, converting "ß" to uppercase becomes "SS".
 4// JavaScript follows this behavior.
 5console.log("\u00DF");
 6console.log("\u00DF".toUpperCase()); // "SS"
 7
 8// Unicode normalization example:
 9// "e\u0301" is "e" + a combining acute accent.
10// "\u00e9" is the precomposed character "é".
11// These two look the same but are different code point sequences.
12const a = "e\u0301";
13const b = "\u00e9";
14
15console.log(a === b);   // false: different underlying code points
16console.log(a.normalize() === b.normalize()); // true: normalized to the same form
  • Unterschiedliche Unicode-Darstellungen, wie Ligaturen und kombinierende Zeichen, sind nicht direkt gleich – verwenden Sie daher vor dem Vergleich normalize().

Unicode und Codepoints (Umgang mit Surrogatpaaren)

JavaScript-Strings sind Sequenzen von UTF-16-Code-Einheiten. Manche Zeichen, wie Emojis, belegen deshalb zwei Code-Einheiten für ein einzelnes Zeichen. Um tatsächliche Zeicheneinheiten zu verarbeiten, verwenden Sie Array.from, den Spread-Operator oder for...of.

 1// Emoji composed with multiple code points:
 2// "\u{1F469}" = woman, "\u{200D}" = Zero Width Joiner (ZWJ),
 3// "\u{1F4BB}" = laptop. Combined, they form a single emoji: 👩‍💻
 4const s = "\u{1F469}\u{200D}\u{1F4BB}";
 5console.log(s);
 6
 7// Length in UTF-16 code units (not actual Unicode characters):
 8// Because this emoji uses surrogate pairs + ZWJ, the length may be > 1.
 9console.log("Length:", s.length);
10
11// Iterate by Unicode code points (ES6 for...of iterates code points):
12// Each iteration gives a full Unicode character, not UTF-16 units.
13for (const ch of s) {
14  console.log(ch);
15}
16
17// Convert to an array of Unicode characters:
18console.log(Array.from(s));
  • length gibt die Anzahl der Code-Einheiten zurück, sodass Sie mit Emojis oder Ligaturen möglicherweise nicht den erwarteten Wert erhalten. for...of und Array.from erfassen fast die dargestellten Zeichen (Graphemcluster), aber für vollständige Graphem-Unterstützung sollten Sie eine spezialisierte Bibliothek verwenden.

Sicheres Ersetzen mit regulären Ausdrücken (bei Benutzereingaben)

Wenn Sie die Benutzereingabe nicht escapen, bevor Sie sie in einen regulären Ausdruck einbetten, kann dies zu unerwartetem Verhalten und Sicherheitslücken führen. Maskieren Sie Benutzereingaben immer, bevor Sie sie in einem Muster verwenden.

1function escapeRegex(s) {
2  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3}
4
5const userInput = "a+b";
6const pattern = new RegExp(escapeRegex(userInput), "g");
7console.log("a+b a+b".replace(pattern, "X")); // "X X"
  • Verwenden Sie Benutzereingaben niemals direkt in regulären Ausdrücken; maskieren Sie sie immer vor der Konstruktion des RegEx.

Performance-Tipps: Verkettung und Templates

Beim Verkettung vieler kleiner Strings hintereinander kann es effizienter sein, sie in ein Array zu legen und mit join zusammenzuführen. Andererseits sind Template-Strings sehr gut lesbar und in den meisten Fällen schnell genug.

 1// concatenation in loop (less ideal)
 2let s = "";
 3for (let i = 0; i < 1000; i++) {
 4  s += i + ",";
 5}
 6
 7// using array + join (often faster for many pieces)
 8const parts = [];
 9for (let i = 0; i < 1000; i++) {
10  parts.push(i + ",");
11}
12const s2 = parts.join("");
  • Moderne JavaScript-Engines sind stark optimiert, daher ist die Performance bei wenigen Verkettungen kein Problem. Wenn Sie jedoch zehntausende Male verketten müssen, ist join möglicherweise effizienter.

Nützliche praktische Techniken: Padding, Trim und Repeat

trim, padStart, padEnd und repeat sind praktische Methoden, die besonders bei der täglichen Zeichenkettenverarbeitung nützlich sind. Sie werden häufig in praktischen Situationen wie dem Formatieren von Eingabewerten oder dem Standardisieren von Ausgabeformaten verwendet.

1console.log("  hello  ".trim());       // "hello"
2console.log("5".padStart(3, "0"));     // "005"
3console.log("x".repeat(5));            // "xxxxx"
  • Diese Methoden können zur Normalisierung von Formulareingaben oder zur Erzeugung von Ausgaben mit fester Breite verwendet werden.

String-Vergleich (lokale Sortierung)

localeCompare ist effektiv, um Strings entsprechend der Wörterbuchreihenfolge verschiedener Sprachen zu vergleichen. Sie können Sprache und Empfindlichkeitsoptionen (wie Groß-/Kleinschreibung) angeben.

1console.log(
2  "\u00E4".localeCompare("z", "de")
3); // may be -1 or other depending on locale
4
5console.log(
6  "a".localeCompare("A", undefined, { sensitivity: "base" })
7); // 0
  • Für internationalisierte Vergleiche verwenden Sie localeCompare und geben die passende Sprache sowie Optionen an.

Praktisches Beispiel: Umwandlung einer CSV-Zeile in ein Objekt (praktischer Workflow)

Ein häufiger Anwendungsfall ist das Parsen einer einzelnen CSV-Zeile zu einem Objekt durch Kombination von split, trim und map. Für Felder mit Anführungszeichen oder komplexe CSV-Dateien verwenden Sie einen spezialisierten CSV-Parser.

 1// simple CSV parse (no quotes handling)
 2function parseCsvLine(line, headers) {
 3  const values = line.split(",").map(v => v.trim());
 4  const obj = {};
 5  headers.forEach((h, i) => obj[h] = values[i] ?? null);
 6  return obj;
 7}
 8
 9const headers = ["name", "age", "city"];
10const line = " Alice , 30 , New York ";
11console.log(parseCsvLine(line, headers));
12// { name: "Alice", age: "30", city: "New York" }
  • Diese Methode funktioniert bei einfachen CSV-Dateien, kann jedoch keine Fälle mit Kommas in Anführungszeichen verarbeiten.

Häufige Fallstricke

Beim Arbeiten mit Strings in JavaScript gibt es einige leicht zu übersehende Spezifikationen und Verhaltensweisen. Um unerwartete Fehler zu vermeiden, sollten Sie die folgenden Punkte beachten.

  • Die Verwendung von new String() kann bei Typüberprüfung oder Vergleichen zu falschen Ergebnissen führen. In den meisten Fällen sind primitive String-Typen ausreichend.
  • Im Unicode kann ein einzelnes sichtbares Zeichen aus mehreren Code-Einheiten bestehen. Deshalb stimmt der von length zurückgegebene Wert möglicherweise nicht mit der tatsächlichen Zeichenanzahl überein.
  • Wenn Sie Benutzereingaben in einen regulären Ausdruck einfügen, maskieren Sie diese immer vorher.
  • String.prototype.replace() ersetzt standardmäßig nur das erste Vorkommen. Wenn Sie alle Vorkommen ersetzen möchten, verwenden Sie das Flag /g in Ihrem regulären Ausdruck.
  • Strings sind unveränderlich, daher liefern Operationen stets einen neuen String zurück. Es ist wichtig, den zurückgegebenen Wert immer zuzuweisen.

Zusammenfassung

Auch wenn JavaScript-Strings einfach erscheinen, ist es wichtig, ihre Eigenschaften bezüglich Unicode und Unveränderlichkeit zu verstehen. Wenn Sie die Grundlagen beherrschen, steigern Sie die Zuverlässigkeit und Lesbarkeit Ihrer String-Verarbeitung erheblich.

Sie können den obigen Artikel mit Visual Studio Code auf unserem YouTube-Kanal verfolgen. Bitte schauen Sie sich auch den YouTube-Kanal an.

YouTube Video