`Array`-objekt
Den här artikeln förklarar om Array-objektet.
Jag kommer att förklara praktiska användningar av arrayer steg för steg på ett lättförståeligt sätt.
YouTube Video
Array-objekt
Array-objektet i JavaScript är en av de viktigaste strukturerna och utgör grunden för all typ av databehandling. Från grundläggande arrayoperationer till högre ordningens funktioner för effektiv datatransformering finns det många funktioner du bör känna till.
Grunderna om arrayer
I JavaScript är arrayer en grundläggande datastruktur för att hantera flera värden tillsammans. Här introducerar vi hur man skapar arrayer samt hur man läser och skriver deras element med enkla exempel.
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
- Denna kod visar tre sätt att skapa arrayer, hur man läser och uppdaterar element med index, samt hur man får längden med
length-egenskapen. - Array-literaler är de vanligaste och mest läsbara, och används oftast i vardagliga situationer.
Lägga till och ta bort element (i slutet eller början)
Arrayer gör det enkelt att lägga till eller ta bort element i början eller slutet. Dessa operationer är också användbara när du implementerar strukturer som stackar eller köer.
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' ]
pushochpoparbetar på slutet av en array. De är idealiska för att implementera stack-strukturer.unshiftochshiftarbetar på början av en array. Var dock medveten om att operationer i början kräver att alla elementindex internt flyttas, vilket gör det till en kostsam operation.
Hantera element i mitten (splice och slice)
När du hanterar element i mitten av en array, välj mellan splice och slice beroende på om du vill ändra den ursprungliga arrayen eller inte. Om du bara vill extrahera en del av en array, använd slice; om du vill modifiera själva arrayen, till exempel genom att infoga eller ta bort element, använd 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 ]
sliceextraherar endast element och modifierar inte den ursprungliga arrayen.splicelägger till eller tar bort element och modifierar själva arrayen, så var särskilt uppmärksam på dess påverkan.
Iteration (for / for...of / forEach)
Det finns flera sätt att bearbeta arrayer sekventiellt, och du kan välja beroende på syfte och kodningsstil. Här är tre typiska loop-konstruktioner.
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-loopen är den mest flexibla och möjliggör indexoperationer och finjusterad kontroll över iteration medbreakoch andra satser.for...ofger ett kortfattat sätt att hantera elementvärden och är bäst balanserad vad gäller läsbarhet.forEachmöjliggör kod i funktionell stil och är väl lämpad för sidoeffekt-operationer, såsom loggning eller uppdatering av data för varje element. Observera dock att du inte kan användabreakellercontinue, och att det inte är lämpligt för asynkron bearbetning medawait.
map / filter / reduce — Funktioner av högre ordning
map, filter och reduce är högre ordningens funktioner som ofta används vid transformering, filtrering eller aggregering av arrayer. Eftersom du tydligt kan uttrycka upprepande bearbetning blir din kod enkel och lätt att förstå.
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
- Dessa metoder låter dig fokusera på vad du vill göra på ett deklarativt sätt, vilket förbättrar läsbarheten och hjälper dig undvika oönskade sidoeffekter.
find / findIndex / some / every
Här är en översikt över sök- och villkorskontrollmetoder. Dessa är användbara för att hitta element som uppfyller vissa villkor eller för att utföra boolesk kontroll av mängder.
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
findreturnerar det första elementet som matchar villkoret.findIndexreturnerar indexet för elementet som matchar villkoret.somereturnerartrueom det finns minst ett element som uppfyller villkoret.everyreturnerartrueom alla element uppfyller villkoret.
Alla dessa är mycket användbara vid arraybearbetning, så att använda dem på ett lämpligt sätt håller din kod kortfattad och tydlig.
Sortering och jämförelsefunktioner
Arrayer sorteras med sort, men som standard jämförs element som strängar, vilket kan ge oväntade resultat vid sortering av tal.
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 sorterar tal eller objekt bör du alltid ange en jämförelsefunktion för att sortera dem i önskad ordning.
- I en jämförelsefunktion innebär ett negativt returvärde att
ahamnar föreb, ett positivt placerarbförea, och 0 behåller deras ordning oförändrad.
Kopiering av arrayer och oföränderlighet
När du kopierar arrayer är det viktigt att förstå skillnaden mellan 'referenskopia' och 'ytlig kopia'. Var särskilt medveten om att om det finns objekt i arrayen kommer en ytlig kopia att dela de inre objekten.
Referenskopia
När du tilldelar en array till en annan variabel dupliceras inte själva arrayen; istället kopieras 'referensen' som pekar på samma array.
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 referenskopia, om du ändrar innehållet i arrayen med den kopierade variabeln, kommer dessa ändringar också att synas i den ursprungliga variabeln som refererar till samma array.
Ytlig kopia
Genom att använda slice() eller spridningssyntaxen skapas en 'ytlig kopia' eftersom endast värdena dupliceras; originalet och kopian av arrayen behandlas som separata 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 ]
- Denna kod visar att en ytlig kopia av en array, skapad med
slice()eller spridningssyntaxen, inte påverkar originalarrayen.
Ytlig kopia och oföränderlighet
Även om du duplicerar en array med en 'ytlig kopia', kan oavsiktlig delning ske om arrayen innehåller objekt inuti.
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 } ]
- Denna kod visar att med en ytlig kopia delas de inre objekten, så att ändringar av dessa inre objekt påverkar både originalarrayen och kopian.
- Om du behöver oberoende data krävs en 'djup kopia', till exempel med
structuredClone()eller JSON-konvertering.
Användbara hjälpfunktioner
Följande är hjälpfunktioner som ofta används när man arbetar med arrayer. Genom att använda dem ändamålsenligt kan du skriva kort och läsbar kod.
includes
Metoden includes kontrollerar om ett visst värde finns med i en 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 denna kod används metoden
includesför att på ett kortfattat sätt avgöra om ett visst värde finns i arrayen.
concat
Metoden concat returnerar en ny array som lägger till den angivna arrayen eller värden i slutet, medan originalarrayen förblir oförändrad.
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 ]
- Denna kod visar att
concatär icke-destruktiv, vilket gör att du kan skapa en ny array och samtidigt behålla originalet.
flat
Med hjälp av metoden flat kan du platta ut nästlade 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 ] ]
- Denna kod visar resultatet av att platta ut en array med ett nivå.
- Eftersom
flatlåter dig ange djupet kan du på ett flexibelt sätt hantera nästling efter behov.
flatMap
Metoden flatMap applicerar en transformation på varje element och plattar sedan automatiskt ut resultatet till en endimensionell 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' ]
- Denna kod visar ett exempel där varje sträng i en array delas upp med mellanslag och resultaten kombineras och plattas ut till en enda array.
join
Metoden join skapar en sträng genom att sammanfoga elementen i en array med ett angivet avgränsningstecken.
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 denna kod används metoden
joinför att omvandla en array till en kommaseparerad sträng.
Vanliga fallgropar
Array-operationer kan verka enkla vid första anblicken, men det finns flera faktorer som lätt leder till oönskat beteende. Många fallgropar är lätta att missa vid dagliga array-operationer, så att hålla dessa punkter i minnet ökar tillförlitligheten i din kod avsevärt.
Array-funktionenssort()sorterar med strängjämförelse som standard. Vid korrekt sortering av tal måste du alltid ange en jämförelsefunktion.- Att kopiera arrayer (med
sliceeller spread-syntax, etc.) skapar en ytlig kopia. Om dina arrayer innehåller objekt, var försiktig eftersom originaldata kan ändras oavsiktligt. spliceär en destruktiv metod som direkt ändrar arrayen, medansliceär en icke-destruktiv metod som inte ändrar den ursprungliga arrayen. Det är viktigt att använda dem på rätt sätt efter dina behov.forEachär inte lämplig för loopar med asynkron bearbetning medawait. Om du vill utföra asynkron bearbetning i ordning på ett säkert sätt, rekommenderas att användafor...of.
Praktiskt exempel
Nedan finns ett exempel som kombinerar array-metoder för att 'få total ålder från användardata, extrahera de som är 30 år eller äldre och skapa en lista med namn.'.
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' ]
- Genom att kedja
reduce,filterochmapkan du enkelt skriva aggregering, villkorsextraktion och datatransformering. - En sådan 'databehandlings-pipeline' är mycket läsbar och, eftersom stilen har få sidoeffekter, är den ofta använd i verkliga applikationer.
Sammanfattning
Med JavaScript-arrayer är även grundläggande operationer allmänt tillämpliga, och genom att använda högre ordningens funktioner blir din kod mer koncis och uttrycksfull. Det finns många punkter att förstå, men när du väl behärskar hur du använder varje del på rätt sätt blir databehandlingen mycket smidigare.
Du kan följa med i artikeln ovan med hjälp av Visual Studio Code på vår YouTube-kanal. Vänligen kolla även in YouTube-kanalen.