FJS26 · V45 · FÖRDJUPNING

Mutable,
immutable
och scope

Vad som händer under ytan när ni skriver b = a, [...a] och const.

Chas Academy · Frontendutveckling


Idag

01Värden och referenser02Mutable och immutable03Spread och rest04Fällan: grund kopia05Öva: skriv om, och en ångra-knapp06Scope
MUTABLE, IMMUTABLE OCH SCOPE2 / 30

UPPVÄRMNING


Vad loggas?

Koden

const a = [1, 2, 3];
const b = a;
b.push(4);

console.log(a);

Er gissning

Skriv ner den innan vi kör. [1, 2, 3] eller [1, 2, 3, 4]? Och varför?

MUTABLE, IMMUTABLE OCH SCOPE3 / 30
01

Värden och
referenser

Del 1 i code-alongen, steg 1–2.

VÄRDEN OCH REFERENSER


Lådor och pilar

Primitivlet x = 5;let y = x;x5y5Värdet kopierasin i lådan.Två lådor, två femmor.Referensconst a = [1, 2, 3];VARIABELMINNETa123Lådan innehåller en piltill arrayen, inte arrayen själv.
MUTABLE, IMMUTABLE OCH SCOPE5 / 30

VÄRDEN OCH REFERENSER


b = a kopierar pilen

const b = a;const a = [1, 2, 3];const b = a;b.push(4);VARIABLERMINNETab1234En array, två namn.a === b → true
MUTABLE, IMMUTABLE OCH SCOPE6 / 30
02

Mutable och
immutable

Del 1, steg 3 och 7–8.

MUTABLE OCH IMMUTABLE


Två sorters värden

Mutable

Går att ändra på plats. Arrayer och objekt. Alla som har en pil dit ser ändringen.

const a = [1, 2, 3];
a.push(4);    // a är ändrad
a[0] = 99;    // a är ändrad

Immutable

Går inte att ändra. Primitiver är alltid immutable. Metoderna returnerar något nytt.

const s = "hej";
s.toUpperCase(); // "HEJ"
console.log(s);  // "hej"
MUTABLE, IMMUTABLE OCH SCOPE8 / 30

MUTABLE OCH IMMUTABLE


Muterar eller skapar nytt?

Ändrar originalet

arr.push(x)
arr.splice(i, 1)
arr.sort()
arr.reverse()
arr[i] = x
obj.x = 1
delete obj.x

Returnerar nytt

[...arr, x]
arr.toSpliced(i, 1)  // eller filter
arr.toSorted()
arr.toReversed()
arr.with(i, x)
{ ...obj, x: 1 }
const { x, ...rest } = obj
MUTABLE, IMMUTABLE OCH SCOPE9 / 30

MUTABLE OCH IMMUTABLE


Varför bry sig?

  • Sidoeffekter. En funktion som muterar det den får ändrar något utanför sig själv. Den som anropar har ingen aning.
  • Förutsägbarhet. Om inget ändras på plats vet du att ett värde ser ut som när du fick det.
  • Historik. Ångra, gör om och jämför bakåt kräver att de gamla versionerna finns kvar.
  • Framåt: React. Ett nytt objekt betyder att något har ändrats. Så vet React när det ska rita om.
MUTABLE, IMMUTABLE OCH SCOPE10 / 30
03

Spread
och rest

Del 1, steg 4–6. 

SPREAD OCH REST


Spread ger en ny array

const c = [...a, 4];const a = [1, 2, 3];const c = [...a, 4];VARIABLERMINNETac1231234← ny arraya === c → false
MUTABLE, IMMUTABLE OCH SCOPE12 / 30

SPREAD OCH REST


Spread i praktiken

Arrayer

const copy = [...numbers];
const withFirst = [0, ...numbers];
const withLast = [...numbers, 4];
const merged = [...a, ...b];

Objekt: sist vinner

const older = { ...ada, age: 37 };

// age skrivs över av ada:
const oops = { age: 37, ...ada };

const settings = { ...defaults, ...choices };
MUTABLE, IMMUTABLE OCH SCOPE13 / 30

SPREAD OCH REST


Samma tre punkter, två jobb

Spread packar uppconst nums = [3, 9, 4];Math.max(...nums);nums394394Där värden används:i anrop, i [ ] och i { }.Rest packar ihopfunction sum(...numbers) { }sum(3, 9, 4);394numbers394Där namn skapas:i parametrar och vid destrukturering.
MUTABLE, IMMUTABLE OCH SCOPE14 / 30

SPREAD OCH REST


Rest i tre lägen

Parametrar

function sum(...values) {
  return values.reduce(
    (t, v) => t + v, 0);
}
sum(1, 2, 3, 4); // 10

Array

const [first, ...others] =
  ["Ada", "Grace", "Linus"];

// others:
// ["Grace", "Linus"]

Objekt

const { password,
  ...publicAccount } = account;

// account är orörd
MUTABLE, IMMUTABLE OCH SCOPE15 / 30
04

Fällan:
grund kopia

Del 1, steg 9–10.

FÄLLAN


Spread kopierar en nivå

Spread är en grund kopiaconst copy = { ...user };copy.address.city = "Malmö";usercopyname:"Ada"address:name:"Ada"address:city:"Malmö"Två yttre objekt, men address delas.
MUTABLE, IMMUTABLE OCH SCOPE17 / 30

FÄLLAN


structuredClone kopierar allt

structuredClone kopierar alla nivåerconst deep = structuredClone(user);deep.address.city = "Malmö";userdeepname:"Ada"address:name:"Ada"address:city:"Lund"city:"Malmö"Inget delas. user är orörd.
MUTABLE, IMMUTABLE OCH SCOPE18 / 30

FÄLLAN


Två sätt att laga det

Sprid även den inre nivån

När du vet exakt vad som ska ändras. Vanligast i praktiken.

const moved = {
  ...user,
  address: { ...user.address, city: "Malmö" },
};

structuredClone

När du behöver en helt fristående kopia.

const deep = structuredClone(user);
deep.address.city = "Malmö";
MUTABLE, IMMUTABLE OCH SCOPE19 / 30
05

Öva

Del 2 och del 3 i code-alongen.

Övning · Del 2

Skriv om utan att mutera

Nio funktioner i 2-ovningar/js/ovningar.js. Alla ger rätt svar, men ändrar det de får. Skriv om dem så att originalet lämnas orört. Sidan rättar när ni laddar om.

Tid

[20 min]

Mål

Alla nio visar ✅. Övning 5 och 6 är svårare: där räcker det inte att kopiera det yttersta.

MUTABLE, IMMUTABLE OCH SCOPE21 / 30

DEL 3 · SPELLISTAN


Därför fungerar inte Ångra

Muterar: inget att ångra tillsongs.push(...) · versions.push(songs)songsversions[1]versions[0]ABCDImmutable: varje steg sparassongs = [...songs, song]songsABCDversions[1]ABCversions[0]AB
MUTABLE, IMMUTABLE OCH SCOPE22 / 30

Code-along · Del 3

Spellistan med ångra-knapp

Lägg till en låt och klicka Ångra. Läs felet. Laga det, och titta på historiken. Skriv sedan om addSong, removeSong, sortSongs och toggleLike så att varje ändring skapar en ny lista.

Tid

[30 min]

Mål

Ångra går ett steg bakåt, även efter att man gillat en låt.

MUTABLE, IMMUTABLE OCH SCOPE23 / 30
06

Scope

Del 4. Samma lådor, men nu handlar det om vem som ser dem.

SCOPE · BRYGGAN


const betyder inte immutable

const låser pilen, inte arrayenconst list = [1];list.push(2); // ✓list = []; // TypeErrorlist12[ ]går inte att peka om
MUTABLE, IMMUTABLE OCH SCOPE25 / 30

SCOPE


Lådor i lådor

Globalt scopeconst playlist = "Fredagsmys";function greet() { }const listener = "Ada";if (playlist) { }const msg = "Hej";console.log(msg, listener, playlist);inre ser utyttre ser inte in
MUTABLE, IMMUTABLE OCH SCOPE26 / 30

SCOPE


Tre sorters scope

Globalt

Högst upp i filen, utanför allt. Syns överallt.

const appName = "Spellistan";

Funktion

Skapat i en funktion, finns bara där.

function makeGreeting() {
  const greeting = "Hej!";
}
// greeting finns inte här

Block

let och const lever mellan { och }.

if (age >= 18) {
  const message = "Ok";
}
// message finns inte här
MUTABLE, IMMUTABLE OCH SCOPE27 / 30

SCOPE


Två saker att se upp med

var läcker

var bryr sig bara om funktioner, inte block. Ni ser det i äldre kod. Använd let och const.

if (true) {
  var leaky = "ut";
}
console.log(leaky); // "ut"

Shadowing

Samma namn i ett inre scope skuggar det yttre. Det yttre ändras inte.

const color = "blå";
function paint() {
  const color = "röd";
}
// color är fortfarande "blå"
MUTABLE, IMMUTABLE OCH SCOPE28 / 30

Övning · Del 4

Vad loggas?

Sex korta funktioner i 4-scope/js/vad-loggas.js. Skriv ner er gissning för varje. Avkommentera sedan ett anrop i taget och kör.

Tid

[15 min]

Mål

Kunna förklara varför, med lådor och pilar. Tre handlar om scope, tre om referenser.

MUTABLE, IMMUTABLE OCH SCOPE29 / 30

SAMMANFATTNING


Att ta med sig

  • Primitiver ligger i lådan. Arrayer och objekt ligger i minnet, och lådan har en pil dit.
  • b = a kopierar pilen. Spread gör en ny array eller ett nytt objekt, men bara en nivå djupt.
  • Arbeta immutabelt: ändra inte det du fått, returnera något nytt.
  • const låser pilen, inte det den pekar på.
  • Scope: inre ser ut, yttre ser aldrig in. let och const stannar i sitt block.
MUTABLE, IMMUTABLE OCH SCOPE30 / 30