Objekter tillader dig at gemme samlinger af vrdier med ngler. Det er fint.
Men meget ofte finder vi ud af, at vi har brug for en ordnet samling, hvor vi har et 1., et 2., et 3. element osv. For eksempel har vi brug for det til at gemme en liste over noget: brugere, varer, HTML-elementer osv.
Det er ikke praktisk at bruge et objekt her, fordi det ikke giver metoder til at hndtere rkkeflgen af elementer. Vi kan ikke indstte en ny egenskab mellem de eksisterende. Objekter er bare ikke beregnet til sdan brug.
Der findes en speciel datastruktur kaldet Array, til at gemme ordnede samlinger.
Deklaration
Der er to syntakser til at oprette et tomt array:
let arr = new Array();
let arr = [];
Nsten altid bruges den anden syntaks. Vi kan angive startvrdier i parenteserne:
let fruits = ["Apple", "Orange", "Plum"];
Array elementer er nummererede, startende fra nul.
Vi kan f et element ved dets nummer i firkantede parenteser:
let fruits = ["ble", "Appelsin", "Blomme"];
alert( fruits[0] ); // ble
alert( fruits[1] ); // Appelsin
alert( fruits[2] ); // Blomme
Vi kan erstatte et element:
fruits[2] = 'Pre'; // now ["ble", "Appelsin", "Pre"]
Eller tilfj en ny til arrayet:
fruits[3] = 'Citron'; // now ["ble", "Appelsin", "Pre", "Citron"]
Det samlede antal elementer i arrayet er dets length:
let fruits = ["ble", "Appelsin", "Blomme"];
alert( fruits.length ); // 3
Vi kan ogs bruge alert til at vise hele arrayet.
let fruits = ["ble", "Appelsin", "Blomme"];
alert( fruits ); // ble,Appelsin,Blomme
Et array kan gemme elementer af enhver type.
For eksempel, det kan vre en blanding af vrdier:
// blanding af vrdier
let arr = [ 'ble', { name: 'Karsten' }, true, function() { alert('hej'); } ];
// henter objektet ved indeks 1 og viser dets navn
alert( arr[1].name ); // Karsten
// henter funktionen ved indeks 3 og krer den
arr[3](); // hej
Et array, ligesom et objekt, kan ende med et komma:
let fruits = [
"ble",
"Appelsin",
"Blomme",
];
Det hngende komma gr det lettere at indstte/fjerne elementer, fordi alle linjer bliver ens.
Hente sidste elementer med at
Lad os sige, at vi vil have det sidste element i arrayet.
Nogle programmeringssprog tillader brugen af negative indekser til det samme forml, som fruits[-1].
Men i JavaScript virker det ikke. Resultatet vil vre undefined, fordi indekset i firkantede parenteser behandles bogstaveligt.
Vi kan eksplicit beregne indekset for det sidste element og derefter f adgang til det: fruits[fruits.length - 1].
let fruits = ["ble", "Appelsin", "Blomme"];
alert( fruits[fruits.length-1] ); // Blomme
En smule besvrligt, ikke? Vi skal skrive variabelnavnet to gange.
Heldigvis findes der en kortere syntaks: fruits.at(-1):
let fruits = ["ble", "Appelsin", "Blomme"];
// Samme som fruits[fruits.length-1]
alert( fruits.at(-1) ); // Blomme
Med andre ord, arr.at(i):
- er prcis det samme som
arr[i], hvisi >= 0. - for negative vrdier af
i, gr det baglns fra slutningen af arrayet.
Metoderne pop/push, shift/unshift
En k er en af de mest almindelige anvendelser af et array. I datalogi betyder det en ordnet samling af elementer, som understtter to operationer:
pushtilfjer et element til slutningen.shifthenter et element fra begyndelsen, hvilket flytter ken frem, s det 2. element bliver det 1.
Arrays understtter begge operationer.
I praksis har vi ofte brug for det. For eksempel en k af beskeder, der skal vises p skrmen.
Der er en anden anvendelse af arrays datastrukturen kaldet stak.
Den understtter to operationer:
pushtilfjer et element til slutningen.pophenter et element fra slutningen.
S nye elementer tilfjes eller tages altid fra enden.
En stak illustreres normalt som en bunke kort: nye kort tilfjes verst eller tages fra verst:
For stakke modtages det senest tilfjede element frst, det kaldes ogs LIFO-princippet (Last-In-First-Out). For ker har vi FIFO (First-In-First-Out).
Arrays i JavaScript kan fungere bde som en k og som en stak. De tillader dig at tilfje/fjerne elementer bde i starten og i slutningen. I datalogi kaldes datastrukturen, der tillader dette, for en deque.
Metoder, der arbejder med slutningen af arrayet:
pop-
Trkker det sidste element ud af arrayet og returnerer det:
let fruits = ["ble", "Appelsin", "Blomme"]; alert( fruits.pop() ); // fjern "Blomme" og vis det alert( fruits ); // ble, AppelsinBde
fruits.pop()ogfruits.at(-1)returnerer det sidste element i arrayet, menfruits.pop()ndrer ogs arrayet ved at fjerne det. push-
Tilfjer elementet til slutningen af arrayet:
let fruits = ["ble", "Appelsin"]; fruits.push("Blomme"); alert( fruits ); // ble, Appelsin, BlommeKaldet
fruits.push(...)svarer tilfruits[fruits.length] = ....
Metoder, der arbejder med begyndelsen af arrayet:
shift-
Trkker det frste element ud af arrayet og returnerer det:
let fruits = ["ble", "Appelsin", "Blomme"]; alert( fruits.shift() ); // fjern "ble" og vis det alert( fruits ); // Appelsin, Blomme unshift-
Tilfjer elementet til begyndelsen af arrayet:
let fruits = ["Appelsin", "Blomme"]; fruits.unshift('ble'); alert( fruits ); // ble, Appelsin, Blomme
Metoderne push og unshift kan tilfje flere elementer p n gang:
let fruits = ["ble"];
fruits.push("Appelsin", "Blomme");
fruits.unshift("Ananas", "Citron");
// ["Ananas", "Citron", "ble", "Appelsin", "Blomme"]
alert( fruits );
Intern opbygning
Et array er en srlig slags objekt. De firkantede parenteser, der bruges til at f adgang til en egenskab arr[0], stammer faktisk fra objektsyntaksen. Det er i bund og grund det samme som obj[key], hvor arr er objektet, mens tal bruges som ngler.
De udvider objekter ved at tilbyde specielle metoder til at arbejde med ordnede samlinger af data og ogs length-egenskaben. Men i kernen er det stadig et objekt.
Husk, der kun er otte grundlggende datatyper i JavaScript (se kapitlet Datatyper for mere info). Array er et objekt og opfrer sig derfor som et objekt.
For eksempel kopieres det ved reference:
let fruits = ["Banan"]
let arr = fruits; // kopier ved reference (to variabler refererer til samme array)
alert( arr === fruits ); // true
arr.push("Pre"); // ndrer arrayet ved reference
alert( fruits ); // Banan, Pre - 2 elementer nu
Men det, der virkelig gr arrays specielle, er deres interne reprsentation. Motoren forsger at gemme elementerne i et sammenhngende hukommelsesomrde, t efter t, som vist p illustrationerne i dette kapitel, og der er ogs andre optimeringer for at f arrays til at kre virkelig hurtigt.
Men de bryder alle sammen, hvis vi holder op med at arbejde med et array som en ordnet samling og begynder at arbejde med det, som om det var et almindeligt objekt.
For eksempel kan vi teknisk set gre dette:
let fruits = []; // lav et array
fruits[99999] = 5; // tildel en egenskab med et indeks langt strre end lngden
fruits.age = 25; // opret en egenskab med et vilkrligt navn
Det er muligt, fordi arrays i bund og grund er objekter. Vi kan tilfje vilkrlige egenskaber til dem.
Men motoren vil se, at vi arbejder med arrayet som med et almindeligt objekt. Array-specifikke optimeringer er ikke egnede til sdanne tilflde og vil blive slet fra, deres fordele forsvinder.
Mder at misbruge et array p:
- Tilfj en ikke-numerisk egenskab som
arr.test = 5. - Lav huller, som: tilfj
arr[0]og derefterarr[1000](og intet imellem). - Fyld arrayet i omvendt rkkeflge, som
arr[1000],arr[999]og s videre.
Tnk venligst p arrays som specielle strukturer til at arbejde med ordnede data. De tilbyder specielle metoder til det. Arrays er omhyggeligt optimeret i JavaScript-motorer til at arbejde med sammenhngende ordnede data, brug dem venligst p denne mde. Og hvis du har brug for vilkrlige ngler, er chancerne store for, at du faktisk har brug for et almindeligt objekt {}.
Performance
Metoderne push/pop krer hurtigt, mens shift/unshift er langsomme.
Hvorfor er det hurtigere at arbejde med enden af et array end med begyndelsen? Lad os se, hvad der sker under udfrelsen:
fruits.shift(); // fjern 1 element fra starten
Det er ikke nok at tage og fjerne elementet med indekset 0. De andre elementer skal ogs omnummereres.
shift-operationen skal gre 3 ting:
- Fjern elementet med indekset
0. - Flyt alle elementer til venstre, omnummerer dem fra indekset
1til0, fra2til1og s videre. - Opdater
length-egenskaben.
Jo flere elementer i arrayet, jo lngere tid tager det at flytte dem, flere operationer i hukommelsen.
Det samme sker med unshift: for at tilfje et element i begyndelsen af arrayet, skal vi frst flytte eksisterende elementer til hjre, hvilket ger deres indekser.
Og hvad med push/pop? De behver ikke at flytte noget. For at fjerne et element fra enden, rydder pop-metoden indekset og forkorter length.
Handlingerne for pop-operationen:
fruits.pop(); // fjern 1 element fra enden
pop-metoden behver ikke at flytte noget, fordi de andre elementer beholder deres indekser. Derfor er den lynhurtig.
Det samme glder for push-metoden.
Lkker
En af de traditionelle mder at gennemlbe array-elementer p er ved at bruge for-loopet over indekser:
let arr = ["ble", "Appelsin", "Pre"];
for (let i = 0; i < arr.length; i++) {
alert( arr[i] );
}
Men for arrays er der en anden form for lkke, for..of:
let fruits = ["ble", "Appelsin", "Blomme"];
// itererer over array-elementer
for (let fruit of fruits) {
alert( fruit );
}
for..of giver ikke adgang til nummeret p det aktuelle element, kun dets vrdi, men i de fleste tilflde er det nok. Og det er kortere.
Teknisk set, fordi arrays er objekter, er det ogs muligt at bruge for..in:
let arr = ["ble", "Appelsin", "Pre"];
for (let key in arr) {
alert( arr[key] ); // ble, Appelsin, Pre
}
Men det er faktisk en drlig id. Der er potentielle problemer med det:
-
Lkken
for..initererer over alle egenskaber, ikke kun de numeriske.Der findes skaldte array-lignende objekter i browseren og i andre miljer, som ligner arrays. Det vil sige, de har
lengthog indeks-egenskaber, men de kan ogs have andre ikke-numeriske egenskaber og metoder, som vi normalt ikke har brug for.for..in-lkken vil dog liste dem. S hvis vi skal arbejde med array-lignende objekter, kan disse ekstra egenskaber blive et problem. -
for..in-lkken er optimeret til generiske objekter, ikke arrays, og derfor er den 10-100 gange langsommere. Selvflgelig er den stadig meget hurtig. Hastighedsfordelen kan kun vre relevant i flaskehalse. Men vi br stadig vre opmrksomme p forskellen.
Generelt br vi ikke bruge for..in til arrays.
Lidt detaljer om length
length-egenskaben opdateres automatisk, nr vi ndrer arrayet. For at vre prcis, er det faktisk ikke antallet af vrdier i arrayet, men den strste numeriske indeks plus n.
For eksempel, et enkelt element med en stor indeks giver en stor lngde:
let fruits = [];
fruits[123] = "ble";
alert( fruits.length ); // 124
Bemrk, at vi normalt ikke bruger arrays p den mde.
En anden interessant ting ved length-egenskaben er, at den kan skrives til.
Hvis vi ger den manuelt, sker der ikke noget interessant. Men hvis vi mindsker den, bliver arrayet forkortet. Processen er irreversibel, her er et eksempel:
let arr = [1, 2, 3, 4, 5];
arr.length = 2; // forkort til 2 elementer
alert( arr ); // [1, 2]
arr.length = 5; // returner lngden tilbage
alert( arr[3] ); // undefined: vrdierne kommer ikke tilbage
S den enkleste mde at rydde arrayet p er: arr.length = 0;.
new Array()
Der er endnu en syntaks til at oprette et array:
let arr = new Array("ble", "Pre", "osv");
Det bruges sjldent, fordi firkantede parenteser [] er kortere. Derudover er der en tricky funktion med det.
Hvis new Array kaldes med et enkelt argument, som er et tal, s opretter det et array uden elementer, men med den givne lngde.
Lad os se hvordan man kan skyde sig selv i foden ved at bruge new Array:
let arr = new Array(2); // vil det oprette et array med [2] ?
alert( arr[0] ); // undefined! intet element.
alert( arr.length ); // length 2
For at undg sdanne overraskelser bruger vi normalt firkantede parenteser, medmindre vi virkelig ved, hvad vi gr.
Flerdimensionale arrays
Arrays kan have elementer, som ogs er arrays. Vi kan bruge det til flerdimensionale arrays, for eksempel til at gemme matricer eller tabeller.:
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
alert( matrix[0][1] ); // 2, den anden vrdi i det frste indre array
toString
Arrays har deres egen implementering af toString-metoden, som returnerer en kommasepareret liste over elementer.
For eksempel, her er et array med tre elementer:
let arr = [1, 2, 3];
alert( arr ); // 1,2,3
alert( String(arr) === '1,2,3' ); // true
Lad os ogs prve dette:
alert( [] + 1 ); // "1"
alert( [1] + 1 ); // "11"
alert( [1,2] + 1 ); // "1,21"
Arrays har ikke Symbol.toPrimitive, heller ikke en brugbar valueOf, de implementerer kun toString-konvertering, s her bliver [] til en tom streng, [1] bliver "1" og [1,2] bliver "1,2".
Nr den binre plus "+" operator lgger noget til en streng, konverterer den det ogs til en streng, s nste trin ser sdan ud:
alert( "" + 1 ); // "1"
alert( "1" + 1 ); // "11"
alert( "1,2" + 1 ); // "1,21"
Sammenlign ikke arrays med ==
Arrays i JavaScript, i modstning til nogle andre programmeringssprog, br ikke sammenlignes med operatoren ==.
Denne operator har ingen srlig behandling for arrays, den fungerer med dem som med enhver anden objekt.
Lad os genopfriske reglerne:
- To objekter er lige
==kun hvis de refererer til det samme objekt. - Hvis et af argumenterne til
==er et objekt, og det andet er en primitiv, s bliver objektet konverteret til en primitiv, som forklaret i kapitlet Konvertering fra objekt til primitiv. - Med undtagelse af
nullogundefined, som er lige==hinanden og intet andet.
Streng sammenligning === er endnu enklere, da den ikke konverterer typer.
S hvis vi sammenligner arrays med ==, er de aldrig ens, medmindre vi sammenligner to variabler, der refererer til prcis det samme array.
For eksempel:
alert( [] == [] ); // false
alert( [0] == [0] ); // false
Disse arrays er teknisk set forskellige objekter. S de er ikke ens. Operatoren == laver ikke element-for-element sammenligning.
Sammenligning med primitivtyper kan ogs give tilsyneladende mrkelige resultater:
alert( 0 == [] ); // true
alert('0' == [] ); // false
I begge tilflde sammenligner vi en primitiv med et array-objekt. S arrayet [] bliver konverteret til en primitiv med henblik p sammenligning og bliver til en tom streng ''.
Sammenligningsprocessen fortstter derefter med primitivtyperne, som beskrevet i kapitlet Konvertering mellem datatyper:
// efter [] blev konverteret til ''
alert( 0 == '' ); // true, da '' bliver konverteret til tallet 0
alert('0' == '' ); // false, ingen typekonvertering, forskellige strenge
S, hvordan sammenligner man arrays?
Det er egentlig simpelt: brug ikke == operatoren. Sammenlign dem i stedet element-for-element i en lkke eller ved hjlp af iterationsmetoder, der forklares i det nste kapitel.
Opsummering
Array er en speciel slags objekt, velegnet til at gemme og hndtere ordnede dataelementer.
Deklarationen:
// firkantede parenteser (almindeligt)
let arr = [item1, item2...];
// new Array (meget sjldent)
let arr = new Array(item1, item2...);
Kaldet til new Array(number) opretter et array med den givne lngde, men uden elementer.
length-egenskaben er arrayets lngde eller, mere prcist, dets sidste numeriske indeks plus en. Den justeres automatisk af array-metoder.- Hvis vi forkorter
lengthmanuelt, bliver arrayet forkortet.
Hentning af elementer:
- vi kan f elementet ved dets indeks, som
arr[0] - vi kan ogs bruge metoden
at(i), som tillader negative indekser. For negative vrdier afitller den baglns fra slutningen af arrayet. Hvisi >= 0, fungerer den somarr[i].
Vi kan bruge et array som en deque med flgende operationer:
push(...items)tilfjeritemstil slutningen.pop()fjerner elementet fra slutningen og returnerer det.shift()fjerner elementet fra begyndelsen og returnerer det.unshift(...items)tilfjeritemstil begyndelsen.
For at gennemlbe elementerne i arrayet, kan vi bruge en af flgende lkker:
for (let i=0; i<arr.length; i++)virker hurtigst, kompatibel med gamle browsere.for (let item of arr)den moderne syntaks for kun elementer,for (let i in arr)brug aldrig.
For at sammenligne arrays, brug ikke == operatoren (eller >, < og andre), da de ikke har nogen srlig behandling for arrays. De hndterer dem som almindelige objekter, og det er ikke, hvad vi normalt nsker.
I stedet kan du bruge en for..of lkke til at sammenligne arrays element-for-element.
Vi fortstter med arrays og studerer flere metoder til at tilfje, fjerne, udtrkke elementer og sortere arrays i det nste kapitel Array-metoder.
Kommentarer
<code>-taggen, for flere linjer - omslut dem i<pre>-tag, for mere end 10 linjer - brug en sandbox (plnkr, jsbin, codepen)