Muterbare og Uforanderlige i TypeScript
Denne artikkelen forklarer konseptene muterbare og uforanderlige i TypeScript.
YouTube Video
Muterbare og Uforanderlige i TypeScript
Hva er Muterbar?
Muterbar betyr at en verdi kan endres. Referansetyper som objekter og arrays er typiske eksempler på muterbare datastrukturer.
Eksempel på et Muterbart 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 koden blir age
-egenskapen til person
-objektet endret fra 25
til 26
. Siden objekter sendes ved referanse, blir innholdet på minneadressen lagret i person
-variabelen modifisert.
Eksempel på et Muterbart Array
1// Mutable Example: Array
2let numbers: number[] = [1, 2, 3];
3numbers.push(4);
4console.log(numbers); // [1, 2, 3, 4]
I denne koden brukes push
-metoden for å legge til et nytt element 4
til det originale arrayet. Dette modifiserer det opprinnelige arrayet, noe som gjør det til en muterbar operasjon.
Eksempel i en Funksjon
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 man utfører muterbare operasjoner inni en funksjon, blir det opprinnelige arrayet også modifisert.
Hva er Uforanderlig?
Uforanderlig betyr at en verdi ikke kan endres. Primitive typer er fundamentalt uforanderlige.
Eksempel på en Uforanderlig Primitiv Type
1// Immutable Example: String
2let str: string = "hello";
3str[0] = "H"; // Error: Index assignment is not allowed
4console.log(str); // "hello"
Forsøk på å endre det første tegnet i strengen str
til H
mislykkes fordi strenger er uforanderlige.
Eksempel i en Funksjon
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)
Siden tall er uforanderlige, påvirker operasjoner inni en funksjon ikke den opprinnelige variabelen.
Uforanderlige Operasjoner på Arrays
Arrays er muterbare, men ved å opprette et nytt array i stedet for å modifisere det originale, kan uforanderlige operasjoner oppnå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 brukes spredningssyntaksen (...
) for å lage en ny liste newNumbers
. Siden den opprinnelige numbers
-listen forblir uendret, er dette en uforanderlig operasjon.
Fordeler med å bruke uforanderlige datastrukturer
Forbedret forutsigbarhet
Uforanderlige data endres ikke, noe som gjør uventede endringer mindre sannsynlige og reduserer sjansen for feil.
Kompatibilitet med biblioteker basert på uforanderlighet
Biblioteker som React
og Redux
er ofte designet med utgangspunkt i uforanderlige data, noe som gjør tilstandshåndtering enklere når det brukes riktig.
Gjøre objekter uforanderlige med Object.freeze
Object.freeze
kan brukes for å forhindre modifikasjoner til 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 }
Imidlertid utfører Object.freeze
kun en overfladisk frysing, noe som betyr at egenskaper i nestede objekter forblir 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 å lage et fullstendig uforanderlig objekt kreves en dyp frysing.
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 endres og inkluderer objekter og lister.
- Uforanderlige data kan ikke endres og inkluderer primitive typer som strenger og tall.
- Ved å bruke spredningssyntaks eller metoder som
map
, kan operasjoner med uforanderlige data utføres. Object.freeze
ogdeepFreeze
kan brukes for å forhindre endringer i objekter.- Bruk av uforanderlige data hjelper med å skrive mer forutsigbar og mindre feilutsatt kode.
Ved å bruke et uforanderlig design forbedres sikkerheten og lesbarheten i koden, så bruk det fullt ut!
Du kan følge med på artikkelen ovenfor ved å bruke Visual Studio Code på vår YouTube-kanal. Vennligst sjekk ut YouTube-kanalen.