‘String’-object

‘String’-object

Dit artikel legt het String-object uit.

De uitleg behandelt alles van de basis tot geavanceerde technieken, inclusief valkuilen met betrekking tot Unicode en reguliere expressies, stap voor stap en op een makkelijk te begrijpen manier.

YouTube Video

‘String’-object

Strings zijn in JavaScript een van de meest gebruikte types in dagelijkse ontwikkeling.

Verschil tussen primitieve strings en string-objecten

Primitieve strings (zoals "hello") gedragen zich anders dan wrapper-objecten zoals new String("hello"). Normaal gesproken moet je de primitieve vorm gebruiken en is er weinig noodzaak om de objectvorm te gebruiken.

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
  • Deze code toont het verschil in type tussen een primitieve string en een wrapper, en hoe ze zich gedragen bij strikte vergelijking. Vermijd in de meeste gevallen het gebruik van new String() en gebruik de primitieve vorm.

Manieren om strings te maken (literal en template literals)

Template literals zijn handig voor het invoegen van variabelen en het schrijven van meerregelige strings. Je kunt variabelen invoegen en expressies op een intuïtieve manier evalueren.

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 literals zijn zeer leesbaar en ideaal voor het bouwen van complexe strings, inclusief meerregelige strings.

Veelgebruikte methoden (zoeken en subtekst extractie)

Het String-object heeft veel basismethoden.

 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 en substring lijken op elkaar, maar behandelen negatieve indexen verschillend. slice interpreteert negatieve waarden als posities vanaf het einde. Wees duidelijk over welke je gebruikt.

Splitsen en Samenvoegen (split / join)

Het is gebruikelijk om een string te splitsen in een array voor verwerking en deze daarna weer samen te voegen.

1const csv = "red,green,blue";
2const arr = csv.split(","); // ["red","green","blue"]
3
4console.log(arr);
5console.log(arr.join(" | ")); // "red | green | blue"
  • Een veelvoorkomend patroon is een string opsplitsen met split, de resulterende array verwerken met map of filter, en deze weer samenvoegen met join.

Vervangen en Reguliere Expressies

replace vervangt alleen de eerste overeenkomst. Als je alle overeenkomsten wilt vervangen, gebruik dan de g-vlag met een reguliere expressie. Door een functie als vervanger door te geven, kun je ook dynamische vervangingen uitvoeren.

 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"
  • Met dynamische vervangingen via een functie kun je beknopte code schrijven die overeenkomsten analyseert en transformeert.

Hoofdlettergevoeligheid en normalisatie

Voor meertalige ondersteuning en vergelijking is naast toLowerCase en toUpperCase ook Unicode-normalisatie (normalize) belangrijk. Dit is vooral noodzakelijk bij het vergelijken van tekens met accenten.

 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
  • Verschillende Unicode-representaties, zoals ligaturen en gecombineerde tekens, zijn niet als vanzelf gelijk, dus gebruik normalize() voor het vergelijken.

Unicode en codepunten (omgaan met surrogaatparen)

JavaScript-strings zijn reeksen van UTF-16 code-eenheden, dus sommige tekens zoals emoji's kunnen twee code-eenheden voor één teken innemen. Om echte tekeneenheden te behandelen, gebruik Array.from, de spread-operator of 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 geeft het aantal code-eenheden terug, dus je krijgt mogelijk niet de verwachte telling bij emoji's of ligaturen. for...of en Array.from behandelen iets wat dicht bij weergegeven tekens ligt (grafemenclusters), maar als je volledige grafemenondersteuning nodig hebt, overweeg dan een gespecialiseerde bibliotheek.

Veilig vervangen met reguliere expressies (bij het verwerken van gebruikersinput)

Als je vergeet om gebruikersinvoer te escapen wanneer je deze in een reguliere expressie verwerkt, kan dit leiden tot onverwacht gedrag en kwetsbaarheden. Escape altijd gebruikersinput voordat je het in een patroon gebruikt.

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"
  • Gebruik gebruikersstrings nooit direct in reguliere expressies; escape ze altijd voordat je de regex maakt.

Prestatie-tips: concatenatie en templates

Bij het achter elkaar samenvoegen van veel kleine strings kan het efficiënter zijn om ze in een array te plaatsen en join te gebruiken. Aan de andere kant zijn template strings zeer leesbaar en in de meeste gevallen snel genoeg.

 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 zijn zeer geoptimaliseerd, dus je hoeft je geen zorgen te maken over prestaties bij een klein aantal samenvoegingen. Moet je echter tienduizenden keren samenvoegen, dan kan het gebruik van join efficiënter zijn.

Handige praktische technieken: opvullen, trimmen en herhalen

trim, padStart, padEnd en repeat zijn handige methoden die vooral nuttig zijn bij alledaagse tekstverwerking. Ze worden vaak gebruikt in praktische situaties, zoals het formatteren van invoerwaarden of het standaardiseren van uitvoerformaten.

1console.log("  hello  ".trim());       // "hello"
2console.log("5".padStart(3, "0"));     // "005"
3console.log("x".repeat(5));            // "xxxxx"
  • Deze methoden kunnen gebruikt worden om formulierinvoer te normaliseren of vaste-breedte-uitvoer te genereren.

Stringvergelijking (vergelijking op basis van lokale instellingen)

localeCompare is effectief voor het vergelijken van strings volgens de woordenboekvolgorde voor verschillende talen. Je kunt taal- en gevoeligheidsopties opgeven (zoals hoofdlettergevoeligheid).

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
  • Gebruik voor geïnternationaliseerde vergelijkingen localeCompare en geef de juiste taal en opties op.

Praktisch voorbeeld: een CSV-rij omzetten naar een object (praktische workflow)

Een veelvoorkomend gebruik is het parsen van een enkele CSV-rij naar een object met een combinatie van split, trim en map. Gebruik voor velden met aanhalingstekens of complexe CSV-bestanden een speciale 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" }
  • Deze methode werkt voor eenvoudige CSV, maar weet dat hij geen gevallen aankan waarbij een komma in een aanhalingstekensveld staat.

Veelvoorkomende valkuilen

Er zijn enkele gemakkelijk over het hoofd geziene specificaties en gedragingen in de stringverwerking in JavaScript. Om onverwachte bugs te voorkomen is het belangrijk de volgende punten in gedachten te houden.

  • Het gebruik van new String() kan tot onjuiste resultaten leiden bij typecontroles of vergelijkingen. In de meeste gevallen zijn primitieve stringtypes voldoende.
  • In Unicode kan een enkel zichtbaar teken uit meerdere code-eenheden bestaan. Daarom kan de waarde die door length wordt teruggegeven, afwijken van het daadwerkelijke aantal weergegeven tekens.
  • Wanneer je gebruikersinput in een reguliere expressie opneemt, escape deze dan altijd eerst.
  • String.prototype.replace() vervangt standaard alleen de eerste overeenkomst. Als je alle voorkomens wilt vervangen, gebruik dan de /g-vlag in je reguliere expressie.
  • Strings zijn onveranderlijk, dus operaties leveren altijd een nieuwe string op. Het is belangrijk altijd de geretourneerde waarde toe te wijzen.

Samenvatting

Hoewel JavaScript-strings eenvoudig lijken, is het belangrijk hun eigenschappen wat betreft Unicode en onveranderlijkheid te begrijpen. Door de basis onder de knie te krijgen kun je de betrouwbaarheid en leesbaarheid van je stringverwerking aanzienlijk verbeteren.

Je kunt het bovenstaande artikel volgen met Visual Studio Code op ons YouTube-kanaal. Bekijk ook het YouTube-kanaal.

YouTube Video