Utvecklarskrivbord med kodeditor på skärm, mekaniskt tangentbord och kaffekopp i sidoljus
Så funkar det

Immutable.js gör state i JavaScript förutsägbart

Immutable.js är ett JavaScript-bibliotek som ger dig datastrukturer som inte kan ändras efter att de skapats. När du modifierar en lista eller en map får du tillbaka en ny version, medan originalet ligger kvar orört. Det låter omständligt men det löser ett av de mest envisa problemen i större JavaScript-projekt: att data ändras på ställen du inte räknat med.

Biblioteket kom från Facebook och har funnits i över ett decennium. Det erbjuder typer som `List`, `Map`, `Set` och `Record` som ersätter de inbyggda arrayerna och objekten. Skillnaden mot vanlig JavaScript är att du aldrig råkar skriva över något av misstag. Varje förändring är ett medvetet val som returnerar en ny struktur.

Föränderligt och oföränderligt fungerar olika i JavaScript

I JavaScript är vissa datatyper oföränderliga från början. Strängar, nummer, booleaner, `null`, `undefined`, `Symbol` och `BigInt` kan inte ändras efter att de skapats. Skriver du `x = 20` och sedan `x = 21` så ersätter du värdet, du ändrar det inte.

Objekt, arrayer och funktioner fungerar tvärtom. De är föränderliga.

”`js

const arr = [1, 2];

arr.push(3); // arr är nu [1, 2, 3], samma array, ändrad

”`

Här är problemet i praktiken: om du skickar in `arr` till en funktion och den funktionen kör `push`, så ändras din ursprungliga array. Du ser kanske aldrig att det hände. I en liten skript spelar det ingen roll. I en applikation med delad state mellan komponenter blir det en jakt på buggar som dyker upp långt från där de orsakades.

Det är precis det som händer när två delar av koden råkar peka på samma objekt. Den ena ändrar, den andra märker det inte. Om du är nyfiken på hur JavaScript faktiskt körs i webbläsaren är det en bra bakgrund för att förstå varför det här spelar roll.

Persistenta datastrukturer delar data smart

Persistenta datastrukturer är kärnan i hur Immutable.js fungerar utan att slösa minne. Namnet är lite missvisande, det handlar inte om att spara till disk. En persistent datastruktur behåller tidigare versioner av sig själv när den uppdateras, så att både den gamla och den nya versionen finns tillgängliga samtidigt.

Den naiva lösningen vore att kopiera hela strukturen vid varje ändring. Det skulle bli outhärdligt långsamt för stora datamängder.

Immutable.js gör något smartare. När du ändrar ett enda element i en stor lista skapas inte en helt ny kopia. Istället delar den nya versionen merparten av sin data med den gamla och bara den delen som faktiskt skiljer sig byggs om. Tekniken kallas structural sharing och bygger på trädstrukturer internt.

Resultatet blir att du får oföränderlighetens trygghet utan att betala fullt pris i prestanda. En uppdatering av ett element i en lista med tiotusen poster kopierar inte tiotusen element, utan bara en handfull noder i trädet.

Så ser koden ut i praktiken

Den största skillnaden mot vanlig JavaScript är att metoder returnerar nya strukturer istället för att ändra på plats.

”`js

const { Map } = require(’immutable’);

const original = Map({ namn: ’Anna’, poäng: 10 });

const uppdaterad = original.set(’poäng’, 20);

original.get(’poäng’); // 10, orört

uppdaterad.get(’poäng’); // 20, ny version

”`

`original` ändras aldrig. `set` ger dig en ny `Map`. Det här är hela poängen: du kan aldrig av misstag skriva över något som en annan del av appen förlitar sig på.

För listor fungerar det likadant. `push`, `set` och `delete` returnerar nya listor istället för att röra originalet. Vill du ut ur Immutable.js värld igen använder du `toJS()` för att konvertera tillbaka till vanliga objekt och arrayer, till exempel när du ska skicka data till ett API.

När Immutable.js är värt det

Biblioteket passar inte alla projekt. Det tillför en egen datamodell som teamet måste lära sig och felmeddelanden blir mindre uppenbara när du blandar Immutable-strukturer med vanlig JavaScript. Här är situationerna där det faktiskt lönar sig:

  • Komplex delad state. När många komponenter läser och uppdaterar samma data och du vill garantera att ingen ändrar något bakom ryggen på en annan.
  • Redux och liknande state-hantering. Oföränderlighet är en grundprincip i Redux och Immutable.js gör det omöjligt att råka mutera state direkt.
  • Snabba jämförelser. Eftersom oföränderliga objekt aldrig ändras kan du jämföra två versioner med referensjämförelse istället för att gå igenom hela strukturen. Det gör det enkelt att avgöra om något faktiskt förändrats, vilket React drar nytta av.
  • Stora datastrukturer som uppdateras ofta. Här gör structural sharing att du slipper kopiera allt vid varje ändring.

För en liten widget eller ett enkelt formulär är biblioteket däremot overkill. Då räcker vanliga objekt och lite disciplin.

ES2023 gjorde inbyggd oföränderlighet enklare

JavaScript har rört sig mot mer förutsägbar datahantering på egen hand. ES2023 introducerade fyra array-metoder som returnerar nya arrayer istället för att ändra originalet, vilket är samma grundidé som Immutable.js bygger på. Du kan se en fullständig översikt av array-metoderna och när du ska använda dem hos Tim Deschryver.

Ny metod (ES2023) Motsvarar Ändrar originalet?
`toSorted()` `sort()` Nej
`toReversed()` `reverse()` Nej
`toSpliced()` `splice()` Nej
`with()` `arr[i] = x` Nej

”`js

const tal = [3, 1, 2];

const sorterad = tal.toSorted(); // [1, 2, 3]

tal; // [3, 1, 2], orört

”`

De här metoderna finns i TypeScript från version 5.2 och uppåt. ES2023 lade dessutom till `findLast()` och `findLastIndex()` för att söka från slutet av en array.

Det betyder inte att Immutable.js blivit överflödigt. De inbyggda metoderna gör grunda kopior och saknar structural sharing, så för stora datamängder eller djupt nästlad state är biblioteket fortfarande starkare. Men för enklare fall slipper du numera ett extra beroende.

Oföränderlighet är en del av en större trend

Rörelsen mot oföränderlig data hänger ihop med ett växande intresse för funktionell programmering i JavaScript. Idén är enkel: om data inte ändras blir kod lättare att resonera om. En funktion som inte kan modifiera sina indata har inga dolda sidoeffekter och då blir det enklare att testa, felsöka och köra parallellt.

Det här syns inte bara i bibliotek som Immutable.js utan i hela ekosystemet. Verktyg som Immer löser samma problem med en annan ansats och språkets egna nya metoder pekar åt samma håll. Vill du förstå hur AI förändrar hur utvecklare faktiskt skriver kod är det en naturlig fortsättning på det här ämnet.

Om du vill förstå grunderna bättre kan det vara värt att repetera hur en webbläsare faktiskt kör din JavaScript och hur API:er skickar data fram och tillbaka, eftersom oföränderlighet ofta blir extra viktigt just där data passerar mellan systemen.

FAQ

Vad är skillnaden mellan Immutable.js och vanliga JavaScript-objekt?

Vanliga objekt och arrayer kan ändras direkt med metoder som `push` eller genom att skriva över en egenskap. Immutable.js strukturer kan inte ändras alls. Varje förändring returnerar en ny version och lämnar originalet orört, vilket gör det omöjligt att av misstag mutera delad data.

Är Immutable.js långsamt eftersom det kopierar data?

Nej. Immutable.js använder structural sharing, vilket betyder att en ny version delar nästan all data med den gamla och bara bygger om den del som ändrats. Att uppdatera ett element i en stor lista kopierar inte hela listan, bara en handfull noder i en intern trädstruktur.

Behöver jag Immutable.js när ES2023 har egna oföränderliga metoder?

Inte alltid. ES2023:s metoder som `toSorted()` och `with()` räcker för enklare fall där du vill undvika att ändra en array på plats. För stora eller djupt nästlade datastrukturer är Immutable.js fortfarande starkare, eftersom de inbyggda metoderna gör grunda kopior utan structural sharing.

Fungerar Immutable.js bra med React och Redux?

Ja. Oföränderlighet är en grundprincip i Redux och Immutable.js gör det omöjligt att råka mutera state direkt. React kan dessutom dra nytta av snabb referensjämförelse för att avgöra om data ändrats, vilket Immutable.js underlättar.

Hur konverterar jag tillbaka till vanlig JavaScript?

Använd metoden `toJS()` på en Immutable-struktur. Den returnerar vanliga objekt och arrayer, vilket är praktiskt när du ska skicka data till ett API eller integrera med kod som inte använder Immutable.js.

Är Immutable.js fortfarande relevant 2026?

Ja, för rätt projekt. Biblioteket har funnits i över ett decennium och löser problem med komplex delad state som de inbyggda metoderna inte täcker fullt ut. För små projekt räcker ofta ES2023:s metoder men för stora applikationer med mycket delad data är persistenta datastrukturer fortfarande ett starkt val.

Källor

  • array-metoderna och när du ska använda dem timdeschryver.dev

Kommentera artikeln

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *