`Array`-objektet
Denne artikkelen forklarer Array-objektet.
Jeg vil forklare praktisk bruk av arrays, trinn for trinn og på en lettfattelig måte.
YouTube Video
Array-objektet
Array-objektet i JavaScript er en av de viktigste strukturene som danner grunnlaget for all slags databehandling. Fra grunnleggende array-operasjoner til høyere ordens funksjoner som er nyttige for effektiv datatransformasjon, er det mange funksjoner du bør kjenne til.
Grunnleggende om arrays
I JavaScript er arrays en grunnleggende datastruktur for å håndtere flere verdier sammen. Her introduserer vi hvordan man lager arrays og hvordan man leser og skriver elementene deres med enkle eksempler.
1// Create arrays in different ways
2const arr1 = [1, 2, 3]; // array literal
3const arr2 = new Array(4, 5, 6); // Array constructor
4const arr3 = Array.of(7, 8, 9); // Array.of
5
6console.log("arr1 created with literal. :", arr1);
7console.log("arr2 created with constructor:", arr2);
8console.log("arr3 created with Array.of. :", arr3);
9// arr1 created with literal. : [ 1, 2, 3 ]
10// arr2 created with constructor: [ 4, 5, 6 ]
11// arr3 created with Array.of. : [ 7, 8, 9 ]
12
13// Access and modify elements
14let first = arr1[0]; // read element
15console.log("First element of arr1:", first);
16// First element of arr1: 1
17
18arr1[1] = 20; // modify element
19console.log("arr1 after modifying index 1:", arr1);
20// arr1 after modifying index 1: [ 1, 20, 3 ]
21
22const len = arr1.length; // get length
23console.log("Length of arr1:", len);
24// Length of arr1: 3
- Denne koden viser tre måter å opprette arrays på, hvordan man leser og oppdaterer elementer ved hjelp av indekser, og hvordan man henter lengden ved å bruke
length-egenskapen. - Array-litteraler er de mest vanlige og lesbare, og brukes oftest i hverdagslige situasjoner.
Legge til og fjerne elementer (på slutten eller begynnelsen)
Arrays lar deg enkelt legge til eller fjerne elementer i enden eller starten. Disse operasjonene er også nyttige når man implementerer strukturer som stabler (stack) eller køer (queue).
1// Push and pop (stack-like)
2const stack = [];
3console.log("Initial stack:", stack);
4
5stack.push(1); // push 1
6console.log("After push(1):", stack);
7
8stack.push(2); // push 2
9console.log("After push(2):", stack);
10
11const last = stack.pop(); // pop -> 2
12console.log("Popped value:", last);
13console.log("Stack after pop():", stack);
14
15// Unshift and shift (queue-like)
16const queue = [];
17console.log("Initial queue:", queue);
18
19queue.push('a'); // add to end
20console.log("After push('a'):", queue);
21
22queue.unshift('start'); // add to front
23console.log("After unshift('start'):", queue);
24
25const firstItem = queue.shift(); // remove from front
26console.log("Shifted value:", firstItem);
27console.log("Queue after shift():", queue);
28
29// Initial stack: []
30// After push(1): [ 1 ]
31// After push(2): [ 1, 2 ]
32// Popped value: 2
33// Stack after pop(): [ 1 ]
34
35// Initial queue: []
36// After push('a'): [ 'a' ]
37// After unshift('start'): [ 'start', 'a' ]
38// Shifted value: start
39// Queue after shift(): [ 'a' ]
pushogpopopererer på slutten av et array. De er ideelle for å implementere stabelstrukturer (stack).unshiftogshiftopererer på begynnelsen av et array. Vær imidlertid oppmerksom på at operasjoner på begynnelsen krever at alle elementindeksene flyttes internt, noe som gjør det til en kostbar operasjon.
Håndtering av elementer i midten (splice og slice)
Når du håndterer elementer i midten av et array, velg mellom splice og slice avhengig av om du vil endre det opprinnelige arrayet eller ikke. Hvis du bare vil hente ut en del av en array, bruk slice; hvis du vil endre selve arrayen, for eksempel ved å sette inn eller slette elementer, bruk splice.
1// slice (non-destructive)
2const nums = [0, 1, 2, 3, 4];
3console.log("Original nums:", nums);
4
5const part = nums.slice(1, 4); // returns [1, 2, 3]
6console.log("Result of nums.slice(1, 4):", part);
7console.log("nums after slice (unchanged):", nums);
8
9// splice (destructive)
10const arr = [10, 20, 30, 40];
11console.log("\nOriginal arr:", arr);
12
13// remove 1 item at index 2, insert 25 and 27
14arr.splice(2, 1, 25, 27);
15console.log("After arr.splice(2, 1, 25, 27):", arr);
16
17// Original nums: [ 0, 1, 2, 3, 4 ]
18// Result of nums.slice(1, 4): [ 1, 2, 3 ]
19// nums after slice (unchanged): [ 0, 1, 2, 3, 4 ]
20
21// Original arr: [ 10, 20, 30, 40 ]
22// After arr.splice(2, 1, 25, 27): [ 10, 20, 25, 27, 40 ]
slicehenter kun ut elementer og endrer ikke det opprinnelige arrayet.splicelegger til eller fjerner elementer og endrer selve arrayet, så vær spesielt oppmerksom på innvirkningen på oppførselen.
Iterasjon (for / for...of / forEach)
Det finnes flere måter å prosessere arrays i rekkefølge, og du kan velge etter formål og hvilken kode-stil du foretrekker. Her er tre typiske løkkekonstruksjoner.
1const items = ['apple', 'banana', 'cherry'];
2console.log("Items:", items);
3
4// classic for
5console.log("\n--- Classic for loop ---");
6for (let i = 0; i < items.length; i++) {
7 console.log(`Index: ${i}, Value: ${items[i]}`);
8}
9
10// for...of (recommended for values)
11console.log("\n--- for...of loop ---");
12for (const item of items) {
13 console.log(`Value: ${item}`);
14}
15
16// forEach (functional style)
17console.log("\n--- forEach loop ---");
18items.forEach((item, index) => {
19 console.log(`Index: ${index}, Value: ${item}`);
20});for-løkka er den mest fleksible og gir mulighet for indeksoperasjoner og presis styring av iterasjonen ved bruk avbreakog andre utsagn.for...ofgir en kortfattet måte å håndtere elementverdier, og er den mest balanserte med tanke på lesbarhet.forEachgjør det mulig med funksjonell stil på koden, og passer godt til operasjoner med bivirkninger som logging eller oppdatering av data for hvert element. Merk imidlertid at du ikke kan brukebreakellercontinue, og at den ikke er egnet for asynkron prosessering medawait.
map / filter / reduce — Høyere ordens funksjoner
map, filter og reduce er høyere-ordens funksjoner som ofte brukes når man transformerer, filtrerer eller grupperer sammen arrayer. Siden du tydelig kan uttrykke repeterende prosessering, blir koden din enkel og lett å forstå.
1const numbers = [1, 2, 3, 4, 5];
2console.log("Original numbers:", numbers);
3
4// map: transform each item
5const doubled = numbers.map(n => n * 2);
6console.log("\nResult of map (n * 2):", doubled);
7
8// filter: select items
9const evens = numbers.filter(n => n % 2 === 0);
10console.log("Result of filter (even numbers):", evens);
11
12// reduce: accumulate to single value
13const sum = numbers.reduce((acc, n) => acc + n, 0);
14console.log("Result of reduce (sum):", sum);
15
16// Original numbers: [ 1, 2, 3, 4, 5 ]
17// Result of map (n * 2): [ 2, 4, 6, 8, 10 ]
18// Result of filter (even numbers): [ 2, 4 ]
19// Result of reduce (sum): 15
- Disse metodene lar deg fokusere på hva du ønsker å gjøre på en deklarativ måte, noe som forbedrer lesbarheten og hjelper deg å unngå uønskede bivirkninger.
find / findIndex / some / every
Her er en oversikt over søke- og betingelsessjekkmetoder. Disse er nyttige for å finne elementer som tilfredsstiller visse betingelser eller for å gjøre boolsk sjekk av settet.
1const users = [
2 { id: 1, name: 'Alice' },
3 { id: 2, name: 'Bob' },
4 { id: 3, name: 'Carol' }
5];
6
7console.log("Users:", users);
8
9// Find the first user whose name is 'Bob'
10const bob = users.find(user => user.name === 'Bob');
11console.log("\nResult of find (name === 'Bob'):", bob);
12
13// Find index of the user whose id is 3
14const indexOfId3 = users.findIndex(user => user.id === 3);
15console.log("Result of findIndex (id === 3):", indexOfId3);
16
17// Check if there exists a user with id = 2
18const hasId2 = users.some(user => user.id === 2);
19console.log("Result of some (id === 2):", hasId2);
20
21// Check if all users have a numeric id
22const allHaveNumericId = users.every(user => typeof user.id === 'number');
23console.log("Result of every (id is number):", allHaveNumericId);
24// Result of find (name === 'Bob'): { id: 2, name: 'Bob' }
25// Result of findIndex (id === 3): 2
26// Result of some (id === 2): true
27// Result of every (id is number): true
findreturnerer det første elementet som tilfredsstiller betingelsen.findIndexreturnerer indeksen til elementet som tilfredsstiller betingelsen.somereturnerertruehvis det finnes minst ett element som tilfredsstiller betingelsen.everyreturnerertruehvis alle elementene tilfredsstiller betingelsen.
Alle disse er svært nyttige ved array-prosessering, så bruk dem riktig etter situasjonen for å holde koden din kort og tydelig.
Sortering og sammenligningsfunksjoner
Arrays blir sortert med sort, men som standard sammenligner den elementene som strenger, noe som kan gi uventede resultater ved sortering av tall.
1const nums = [10, 2, 33, 4];
2console.log("Original nums:", nums);
3
4// Default sort: compares elements as strings (not suitable for numbers)
5nums.sort();
6console.log("\nAfter default sort (string comparison):", nums);
7
8// Numeric ascending sort using a compare function
9nums.sort((a, b) => a - b);
10console.log("After numeric sort (a - b):", nums);
11
12// Sort objects by a property
13const people = [{ age: 30 }, { age: 20 }, { age: 25 }];
14console.log("\nOriginal people:", people);
15
16people.sort((a, b) => a.age - b.age);
17console.log("After sorting people by age:", people);
18
19// After default sort (string comparison): [ 10, 2, 33, 4 ]
20// After numeric sort (a - b): [ 2, 4, 10, 33 ]
21// Original people: [ { age: 30 }, { age: 20 }, { age: 25 } ]
22// After sorting people by age: [ { age: 20 }, { age: 25 }, { age: 30 } ]
- Når du sorterer tall eller objekter, må du alltid spesifisere en sammenligningsfunksjon for å sortere dem i ønsket rekkefølge.
- I en sammenligningsfunksjon plasserer en negativ returverdi
aforanb, en positiv plassererbforana, og 0 beholder rekkefølgen uendret.
Kopiering av arrays og uforanderlighet
Når du kopierer arrayer, er det viktig å forstå forskjellen mellom 'referansekopi' og 'shallow copy'. Vær spesielt oppmerksom på at dersom det finnes objekter inne i arrayet, vil en grunn kopi føre til at de interne objektene blir delt.
Referansekopi
Når du tildeler et array til en annen variabel, dupliseres ikke selve arrayet; i stedet kopieres 'referansen' som peker til det samme arrayet.
1const a = [1, 2, 3];
2console.log("Original a:", a);
3
4// Reference copy; modifying b also affects a
5const b = a;
6console.log("\nReference copy b = a:", b);
7// Reference copy b = a: [ 1, 2, 3 ]
8
9b[0] = 100;
10console.log("After modifying b[0] = 100:");
11console.log("a:", a); // a: [ 100, 2, 3 ] (affected)
12console.log("b:", b); // b: [ 100, 2, 3 ]
- Med en referansekopi, hvis du endrer innholdet i arrayet ved å bruke den kopierte variabelen, vil disse endringene også gjenspeiles i den opprinnelige variabelen som refererer til det samme arrayet.
Shallow copy
Ved å bruke slice() eller spread-syntaksen lages en 'shallow copy' fordi kun verdiene blir duplisert; det opprinnelige og det kopierte arrayet behandles som separate enheter.
1const a = [1, 2, 3];
2console.log("Original a:", a);
3
4// Shallow copy (new array)
5const b = a.slice();
6console.log("\nShallow copy using slice():", b);
7// Shallow copy using slice(): [ 100, 2, 3 ]
8
9const c = [...a];
10console.log("Shallow copy using spread [...a]:", c);
11// Shallow copy using spread [...a]: [ 100, 2, 3 ]
12
13// Modifying c or d does NOT affect a
14b[1] = 200;
15c[2] = 300;
16console.log("\nAfter modifying b[1] = 200 and c[2] = 300:");
17console.log("a:", a); // [ 100, 2, 3 ]
18console.log("b:", b); // [ 100, 200, 3 ]
19console.log("c:", c); // [ 100, 2, 300 ]
- Denne koden viser at en shallow copy av et array laget med
slice()eller spread-syntaksen ikke påvirker det opprinnelige arrayet.
Shallow copy og imutabilitet
Selv om du dupliserer et array ved å bruke en 'shallow copy', kan utilsiktet deling oppstå hvis arrayet inneholder objekter.
1// Shallow copy doesn't clone inner objects
2const nested = [{ x: 1 }, { x: 2 }];
3console.log("\nOriginal nested:", nested);
4// Original nested: [ { x: 1 }, { x: 2 } ]
5
6const shallow = nested.slice();
7console.log("Shallow copy of nested:", shallow);
8// Shallow copy of nested: [ { x: 1 }, { x: 2 } ]
9
10// Changing inner object affects both arrays
11shallow[0].x = 99;
12console.log("\nAfter shallow[0].x = 99:");
13console.log("nested:", nested);
14console.log("shallow:", shallow);
15// nested: [ { x: 99 }, { x: 2 } ]
16// shallow: [ { x: 99 }, { x: 2 } ]
- Denne koden viser at med en shallow copy deles de indre objektene, så endringer i disse vil påvirke både det opprinnelige arrayet og kopien.
- Hvis du trenger uavhengige data, må du foreta en 'dyp kopi' for eksempel ved å bruke
structuredClone()eller ved JSON-konvertering.
Nyttige hjelpe-metoder
Følgende er hjelpemetoder som ofte brukes når man jobber med arrays. Ved å bruke disse riktig for ditt formål, kan du skrive kort og lesbar kode.
includes
includes-metoden sjekker om en spesifikk verdi finnes i et array.
1// includes: check if array contains a value
2const letters = ['a', 'b', 'c'];
3const hasB = letters.includes('b');
4console.log("letters:", letters); // [ 'a', 'b', 'c' ]
5console.log("letters.includes('b'):", hasB); // true
- I denne koden brukes
includes-metoden for å enkelt avgjøre om en angitt verdi finnes i arrayet.
concat
concat-metoden returnerer et nytt array hvor det spesifiserte arrayet eller verdier legges til på slutten, mens det opprinnelige arrayet forblir uendret.
1// concat: merge arrays without mutation
2const a1 = [1, 2];
3const a2 = [3, 4];
4const combined = a1.concat(a2);
5console.log("a1.concat(a2):", combined); // [ 1, 2, 3, 4 ]
6console.log("a1(unchanged):", a1); // [ 1, 2 ]
- Denne koden viser at
concatikke ødelegger det opprinnelige arrayet, slik at du kan generere et nytt array og samtidig beholde det gamle.
flat
Ved å bruke flat-metoden kan du flate ut nestede arrayer.
1// flat and flatMap: flatten arrays or map + flatten in one step
2const nested = [1, [2, [3]]];
3console.log("nested:", nested); // nested: [ 1, [ 2, [ 3 ] ] ]
4console.log("nested.flat():", nested.flat()); // default depth = 1
5// nested.flat(): [ 1, 2, [ 3 ] ]
- Denne koden viser resultatet av å flate ut et array med ett nivå.
- Siden
flatlar deg spesifisere dybden, kan du fleksibelt løse opp nestinger etter behov.
flatMap
flatMap-metoden bruker en transformasjon på hvert element og flater deretter resultatene automatisk ut til et endimensjonalt array.
1// flat and flatMap: flatten arrays or map + flatten in one step
2const words = ['hello world', 'hi'];
3console.log("words:", words); // [ 'hello world', 'hi' ]
4
5const splitWords = words.flatMap(w => w.split(' '));
6console.log("words.flatMap(w => w.split(' ')):", splitWords);
7// words.flatMap(w => w.split(' ')): [ 'hello', 'world', 'hi' ]
- Denne koden viser et eksempel der hver streng i et array deles opp med mellomrom, og resultatene samles og flates ut til ett enkelt array.
join
join-metoden lager en streng ved å sette sammen elementene i et array med en angitt separator.
1// join: combine elements into a string with a separator
2const csv = ['a', 'b', 'c'].join(',');
3console.log("['a', 'b', 'c'].join(','):", csv); // a,b,c
- I denne koden brukes
join-metoden for å konvertere et array til en kommaseparert streng.
Vanlige fallgruver
Array-operasjoner kan virke enkle ved første øyekast, men det finnes flere punkter som lett kan føre til uønsket oppførsel. Mange fallgruver er lette å overse i daglig bruk av arrays, så å ha følgende punkter i bakhodet vil forbedre påliteligheten til koden din betraktelig.
Arraysinsort()sorterer etter strengsammenligning som standard. Når du skal sortere tall riktig, må du alltid oppgi en sammenligningsfunksjon.- Kopiering av arrays (via
sliceeller spread-syntaks, etc.) gir en grunn kopi. Hvis arrayene dine inneholder objekter, vær obs på at de opprinnelige dataene kan bli utilsiktet endret. spliceer en destruktiv metode som endrer arrayet direkte, menssliceer en ikke-destruktiv metode som ikke endrer det opprinnelige arrayet. Det er viktig å bruke dem riktig etter behov.forEacher ikke egnet til løkker med asynkron prosessering medawait. Hvis du vil utføre asynkrone operasjoner pålitelig i rekkefølge, anbefales det å brukefor...of.
Praktisk eksempel
Nedenfor er et eksempel som kombinerer array-metoder for å 'finne totalalderen fra brukerdata, hente ut dem som er 30 år eller eldre, og opprette en navneliste.'.
1const users = [
2 { name: 'Alice', age: 28 },
3 { name: 'Bob', age: 34 },
4 { name: 'Carol', age: 41 },
5 { name: 'Dave', age: 19 }
6];
7
8console.log("Users:", users);
9
10// sum ages
11const totalAge = users.reduce((acc, u) => acc + u.age, 0);
12console.log("\nTotal age of all users:", totalAge);
13// Total age of all users: 122
14
15// filter and map names of users 30 and older
16const namesOver30 = users
17 .filter(u => u.age >= 30)
18 .map(u => u.name);
19
20console.log("Users aged 30 or older (names):", namesOver30);
21// Users aged 30 or older (names): [ 'Bob', 'Carol' ]
- Ved å kjede sammen
reduce,filterogmap, kan du enkelt skrive aggregering, hente ut bestemte betingelser, og transformere data. - En slik 'databehandlings-pipeline' er svært lettlest, og som en stil med få bivirkninger brukes dette ofte i virkelige applikasjoner.
Sammendrag
Med JavaScript-arrays er selv grunnleggende operasjoner mye brukt, og ved å bruke høyere ordens funksjoner blir koden din mer konsis og uttrykksfull. Det er mye å forstå, men når du først har lært å bruke disse riktig, vil databehandlingen gå langt smidigere.
Du kan følge med på artikkelen ovenfor ved å bruke Visual Studio Code på vår YouTube-kanal. Vennligst sjekk ut YouTube-kanalen.