Mutable og Immutable i TypeScript
Denne artikel forklarer mutable og immutable begreber i TypeScript.
YouTube Video
Mutable og Immutable i TypeScript
Hvad er Mutable?
Mutable betyder, at en værdi kan ændres. Referencetyper som objekter og arrays er typiske eksempler på mutable datastrukturer.
Eksempel på et Mutable Objekt
1type Person = { name: string; age: number };
2
3// Mutable Example: Object
4let person: Person = { name: "Alice", age: 25 };
5person.age = 26;
6console.log(person); // { name: "Alice", age: 26 }
I denne kode ændres age
-egenskaben for person
-objektet fra 25
til 26
. Da objekter videregives som reference, ændres indholdet på hukommelsesadressen gemt i person
-variablen.
Eksempel på et Mutable Array
1// Mutable Example: Array
2let numbers: number[] = [1, 2, 3];
3numbers.push(4);
4console.log(numbers); // [1, 2, 3, 4]
I denne kode bruges push
-metoden til at tilføje et nyt element 4
til det originale array. Dette ændrer det originale array, hvilket gør det til en mutable operation.
Eksempel i en Funktion
1// Mutable Example: Function
2function append(arr: number[], value: number): void {
3 arr.push(value); // Modify the original array
4 console.log(arr);
5}
6
7let nums: number[] = [1, 2, 3];
8append(nums, 4);
9console.log(nums); // [1, 2, 3, 4]
Når mutable operationer udføres inde i en funktion, ændres det originale array også.
Hvad er Immutable?
Immutable betyder, at en værdi ikke kan ændres. Primitive typer er grundlæggende immutable.
Eksempel på en Immutabel Primitiv Type
1// Immutable Example: String
2let str: string = "hello";
3str[0] = "H"; // Error: Index assignment is not allowed
4console.log(str); // "hello"
Forsøg på at ændre det første tegn i strengen str
til H
mislykkes, fordi strenge er immutable.
Eksempel i en Funktion
1// Immutable Example: Function
2function increment(num: number): number {
3 num++; // This modifies only the local copy of num
4 return num;
5}
6
7let number: number = 10;
8console.log(increment(number)); // 11
9console.log(number); // 10 (original number remains unchanged)
Da tal er immutable, påvirker operationer inde i en funktion ikke den originale variabel.
Immutable Operationer på Arrays
Arrays er mutable, men ved at oprette et nyt array i stedet for at ændre det originale, kan immutable operationer opnås.
1// Create an array of numbers
2let numbers: number[] = [1, 2, 3];
3
4// Immutable Example: Creating a new array
5let newNumbers: number[] = [...numbers, 4];
6
7console.log(numbers); // [1, 2, 3] (original array is unchanged)
8console.log(newNumbers); // [1, 2, 3, 4] (new array with an added element)
Her bruges spredningssyntaksen (...
) til at oprette et nyt array newNumbers
. Da det originale numbers
array forbliver uændret, er dette en uforanderlig operation.
Fordele ved at bruge uforanderlige datastrukturer
Forbedret forudsigelighed
Uforanderlige data ændrer sig ikke, hvilket gør uventede ændringer mindre sandsynlige og reducerer risikoen for fejl.
Kompatibilitet med biblioteker baseret på uforanderlighed
Biblioteker som React
og Redux
er ofte designet baseret på uforanderlige data, hvilket gør tilstandshåndtering lettere, når de bruges korrekt.
Gør objekter uforanderlige med Object.freeze
Object.freeze
kan bruges til at forhindre ændringer i et objekt.
1// Create a frozen object (properties cannot be modified)
2const person = Object.freeze({ name: "Alice", age: 25 });
3
4// Attempt to modify a property (ignored in non-strict mode, error in strict mode)
5person.age = 26;
6
7console.log(person); // { name: "Alice", age: 25 }
Dog udfører Object.freeze
kun en overfladisk fryser, hvilket betyder, at egenskaberne i indlejrede objekter forbliver foranderlige.
1// Create a frozen object with a nested object
2const user: Readonly<{ profile: { name: string } }> = Object.freeze({
3 profile: { name: "Bob" }
4});
5
6// Attempt to modify a nested property (this works because Object.freeze() is shallow)
7user.profile.name = "Charlie"; // No TypeScript error, but still mutable
8
9console.log(user.profile.name); // "Charlie" (nested object is still mutable)
For at skabe et helt uforanderligt objekt kræves en dyb fryser.
1// Function to deeply freeze an object, making all nested objects immutable
2function deepFreeze<T>(obj: T): Readonly<T> {
3 Object.freeze(obj);
4 Object.getOwnPropertyNames(obj).forEach(prop => {
5 const value = (obj as any)[prop];
6 if (typeof value === "object" && value !== null) {
7 deepFreeze(value);
8 }
9 });
10 return obj;
11}
12
13// Create a deeply frozen object
14const user = deepFreeze({
15 profile: { name: "Bob" }
16});
17
18// Attempt to modify a nested property
19// (this will now throw an error in strict mode)
20user.profile.name = "Charlie"; // No TypeScript error, but modification is not allowed at runtime
21
22console.log(user.profile.name); // "Bob" (unchanged due to deep freeze)
Sammendrag
- Foranderlige data kan ændres og inkluderer objekter og arrays.
- Uforanderlige data kan ikke ændres og inkluderer primitive typer såsom strenge og tal.
- Ved at bruge spredningssyntaks eller metoder som
map
kan uforanderlige dataoperationer udføres. Object.freeze
ogdeepFreeze
kan bruges til at forhindre ændringer i objekter.- Brug af uforanderlige data hjælper med at skrive mere forudsigelig og mindre fejlsikker kode.
Ved at adoptere et uforanderligt design forbedres kodesikkerhed og læsbarhed, så udnyt det fuldt ud!
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.