`String`-objektet
Denne artikel forklarer String-objektet.
Forklaringen dækker alt fra det grundlæggende til avancerede teknikker, inklusive faldgruber relateret til Unicode og regulære udtryk, trin for trin og på en letforståelig måde.
YouTube Video
String-objektet
Strings i JavaScript er en af de mest anvendte typer i daglig udvikling.
Forskel mellem primitive strings og String-objekter
Primitive strings (som "hello") opfører sig anderledes end wrapper-objekter som new String("hello"). Normalt bør du bruge primitive strenge, og der er sjældent brug for objekttypen.
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
- Denne kode viser forskellen i type mellem en primitiv streng og en wrapper, og hvordan de opfører sig ved streng sammenligning. I de fleste tilfælde bør du undgå at bruge
new String()og holde dig til primitive strenge.
Måder at oprette strenge på (literals og skabelonstrenge)
Skabelonstrenge er nyttige til at indsætte variabler og skrive flersporede strenge. Du kan intuitivt indsætte variabler og evaluere udtryk.
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"
- Skabelonstrenge er meget læsbare og ideelle til at bygge komplekse strenge, også med flere linjer.
Almindelige metoder (søgning og udtrækning af delstrenge)
String-objektet har mange grundlæggende metoder.
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"
sliceogsubstringligner hinanden, men håndterer negative indekser forskelligt.slicefortolker negative værdier som positioner fra slutningen. Vær sikker på hvilken du skal bruge.
Opdeling og sammenføjning (split / join)
Det er almindeligt at dele en streng op i et array til behandling og derefter samle den igen.
1const csv = "red,green,blue";
2const arr = csv.split(","); // ["red","green","blue"]
3
4console.log(arr);
5console.log(arr.join(" | ")); // "red | green | blue"
- Et almindeligt mønster er at bruge
splittil at dele en streng, bearbejde det resulterende array medmapellerfilter, og derefter brugejointil at samle det igen.
Udskiftning og regulære udtryk
replace udskifter kun det første match. Hvis du vil udskifte alle matches, skal du bruge g-flaget med et regulært udtryk. Ved at videregive en funktion som erstatning, kan du også udføre dynamiske udskiftninger.
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"
- Med dynamisk udskiftning via en funktion kan du skrive kortfattet kode, der analyserer og transformerer matches.
Skift af store/små bogstaver og normalisering
For flersproget support og sammenligning er Unicode-normalisering (normalize) også vigtig, ud over toLowerCase og toUpperCase. Dette er især nødvendigt ved sammenligning af bogstaver med accent.
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
- Forskellige Unicode-repræsentationer, såsom ligaturer og kombinerede tegn, er ikke ens som de er, så brug
normalize()før du sammenligner.
Unicode og kodepunkter (håndtering af surrogatpar)
JavaScript-strenge er sekvenser af UTF-16 kodeenheder, så visse tegn som emojis kan bruge to kodeenheder for ét tegn. For at håndtere reelle tegn, brug Array.from, spread-operatoren eller 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));lengthreturnerer antallet af kodeenheder, så du får måske ikke det forventede antal ved emojis eller ligaturer.for...ofogArray.frombehandler noget tæt på de viste tegn (grapheme clusters), men hvis du har brug for fuld støtte til grafemer, bør du bruge et specialiseret bibliotek.
Sikker udskiftning med regulære udtryk (ved håndtering af brugerinput)
Hvis du glemmer at escape brugerinput, når du indsætter det i et regulært udtryk, kan det føre til uventet adfærd og sårbarheder. Escape altid brugerinput før du bruger det i et mønster.
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"
- Brug aldrig brugerstrenge direkte i regulære udtryk; escape dem altid før du opretter regexen.
Ydelsestips: Sammenkædning og skabelonstrenge
Når du sammenkæder mange små strenge i rækkefølge, kan det være mere effektivt at lægge dem i et array og bruge join. På den anden side er skabelonstrenge meget læsbare og hurtige nok i de fleste tilfælde.
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-motorer er meget optimerede, så du behøver ikke bekymre dig om ydeevne ved et lille antal sammenkædninger. Dog kan det være mere effektivt at bruge
join, hvis du skal sammenkæde titusindvis af gange.
Nyttige praktiske teknikker: udfyldning, trimning og gentagelse
trim, padStart, padEnd og repeat er praktiske metoder, som især er nyttige i den daglige strengbehandling. De bruges ofte i praktiske situationer som formatering af inputværdier eller standardisering af outputformater.
1console.log(" hello ".trim()); // "hello"
2console.log("5".padStart(3, "0")); // "005"
3console.log("x".repeat(5)); // "xxxxx"
- Disse metoder kan bruges til at normalisere formularinput eller generere output med fast bredde.
Strengsammenligning (lokalesammenligning)
localeCompare er effektivt til at sammenligne strenge i ordbogsorden for forskellige sprog. Du kan angive sprog og følsomhedsindstillinger (såsom store/små bogstaver).
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
- Til internationaliseret sammenligning, brug
localeCompareog angiv den relevante locale og indstillinger.
Praktisk eksempel: Konvertering af en CSV-række til et objekt (praktisk arbejdsgang)
Et almindeligt brugstilfælde er at omdanne en enkelt CSV-række til et objekt ved at bruge en kombination af split, trim og map. For felter med anførselstegn eller komplekse CSV-filer, brug en dedikeret 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" }
- Denne metode fungerer til simpel CSV, men vær opmærksom på, at den ikke kan håndtere tilfælde, hvor et komma er inde i et citeret felt.
Almindelige faldgruber
Der er nogle let oversete specifikationer og adfærd i JavaScript-strenghåndtering. For at undgå uventede fejl er det vigtigt at have følgende punkter i tankerne.
- Brug af
new String()kan føre til forkerte resultater ved typekontrol eller sammenligninger. I de fleste tilfælde er primitive strenge tilstrækkelige. - I Unicode kan et enkelt synligt tegn bestå af flere kodeenheder. Derfor matcher værdien returneret af
lengthmåske ikke det faktiske antal viste tegn. - Når du bruger brugerinput i et regulært udtryk, skal du altid escape det først.
String.prototype.replace()udskifter kun det første match som standard. Hvis du vil erstatte alle forekomster, skal du bruge/g-flaget i dit regulære udtryk.- Strenge er uforanderlige, så operationer returnerer altid en ny streng. Det er vigtigt altid at tildele den returnerede værdi.
Sammendrag
Selvom JavaScript-strenge måske virker simple, er det vigtigt at forstå deres egenskaber i forhold til Unicode og uforanderlighed. Ved at mestre det grundlæggende kan du i høj grad forbedre pålideligheden og læsbarheden af din strengbehandling.
Du kan følge med i ovenstående artikel ved hjælp af Visual Studio Code på vores YouTube-kanal. Husk også at tjekke YouTube-kanalen.