Artikel top billede

(Foto: Computerworld)

JavaScript del 2: Klasseløse objekter

I det første afsnit af serien om Javascript, læste du om Javascript som et proceduralt programmeringssprog. Men Javascript er meget mere end det. Sproget er også objekt-orienteret, og denne gang kigger vi nærmere på objekter, og hvordan de bruges.

Af Rasmus Elm Rasmussen, Alt om Data

Denne artikel er oprindeligt bragt på Alt om Data. Computerworld overtog i november 2022 Alt om Data. Du kan læse mere om overtagelsen her.

Der er stor sandsynlighed for, at du kender til objektorienteret programmering, hvis du tidligere har arbejdet med sprog som Delphi, C++, PHP eller Java. JavaScripts måde at arbejde med objekter er noget forskellig fra disse sprog. Ikke forstået som, at du bare kan glemme alt, hvad du tidligere har lært, men JavaScripts objekter kræver, at du bliver nødt til at vende dem et par gange inde i dit hoved, før du kan udnytte dem fuldt ud.

Sprog som C++ og Java har klasser. Et objekt er en instans af et objekt, og på den måde minder klasser meget om typer. Ja, nogle sprog (Smalltalk og Ruby for at nævne et par) går så langt, at alt er objekter – selv tallet 42 er et objekt.

I JavaScript findes der ikke klasser, men objekter oprettes og udvides dynamisk, mens dit program afvikles. Klasser er derimod meget sta-tiske – de kan ikke ændres, når programmet først er gået i gang. Det betyder, at programmøren skal tage hensyn til alle anvendelsesmulig-heder, når hun skriver programmet. Med JavaScript kan de klasseløse objekter ændres, og det kan give mere kompakte og mere læsbare programmer.

Enkle objekter

Inden du kastes ud i en længere afhandling om klasseløse objekter, er det på sin plads at introducere objekter og deres syntaks. JavaScript har nogle basale typer, som ikke er objekter. Det er tal, strenge og logiske værdier (»sand« og »falsk«). Alt andet er objekter, inklusive tabeller (»arrays«) og regulære udtryk. Selvom strenge ikke er objekter, fungerer de ofte, som om de er.

Med alt menes alt – funktioner er også objekter og kan manipuleres på samme måde som alle andre objekter. Det er emnet for det tredje afsnit i serien, hvor vi vender tilbage til funktionsobjekter og uddyber det.

Et objekt er en samling af nøgle-/værdi-par (objekter kan godt være tomme). Nøgle-/værdi-parrene skrives i krøllet parentes ({} - også kal-det Tuborg). I infoboks »Enkle objekter« kan du se et par eksempler. Du ser også forskellige måder, hvorpå du kan tilgå værdierne i et objekt.

Både kantet parentes ([]) og punktum (.) er gyldige, men det anbefales, at du bruger punktum. I nogle sprog omtales nøglerne som »med-lemmer« eller »attributter«, men de fungerer på samme måde. I JavaScript kan du ikke umiddelbart gemme en nøgle/et medlem på samme måde, som du kan i f.eks. Java.

Det er også muligt at tildele nye værdier direkte til en af nøglerne, som det også fremgår i eksemplet. På samme måde er det muligt at op-rette nye nøgler ved blot at tildele dem en værdi. Har objektet ikke en nøgle (svante.titel i eksemplet), returneres værdien »undefined«.

Det er utroligt stærkt at kunne tilføje nøgler og værdier, mens et program kører. Men det er mindst ligeså stærkt at kunne slette et nøgle-/værdi-par under kørslen. JavaScript har en operator til det formål. I infoboks »Slet en nøgle« kan du se, hvordan operatoren »delete« kan bruges. Først har alder værdien »40«, men i sidste linje (efter »delete«) er værdien af »kenneth.alder« sat til »undefined«, da denne nøgle ikke længere findes.

Komplekse objekter

Objekter i JavaScript kan have en vilkårlig kompleksitet forstået på den måde, at værdien af en nøgle kan være alle gyldige objekter (og her tælles tal og strenge med). Det betyder, at et objekt er en gyldig værdi, og du kan elegant bygge træstrukturer og lignende op. I infoboks »Komplekse objekter« finder du en række eksempler.

Både far og mor er selv objekter, mens barn er et array af objekter. I slutningen af eksemplet kan du se, at du ved at bruge punktum kan få adgang til værdien inde i et objekts objekt (»familie.far.alder«).

Eftersom funktioner kan betragtes som objekter, kan de også bruges som værdier til nøgler. Det er den måde, at JavaScript giver objekterne metoder, som du kender det fra C++ og Java. Det elegante her er blot, at du kan tilføje – og fjerne – metoder, mens programmet afvikles. I eksemplet finder du én metode, nemlig alder, som udregner familiens totale alder.

Metoderne har adgang til deres objekt gennem en særlig variabel ved navn »this«. Denne variabel er en reference til objektet, og du kan ved at bruge den få adgang til alle nøgler (attributter og meto-der) og deres værdier.

Refleksion

I objektorienteret programmering finder du et begreb ved navn »refleksion«. Det lyder avanceret, men det er i virkeligheden blot en teknik til at få information om, hvad et objekt indeholder – uden på forhånd at vide det. Refleksion er en vigtig teknik, når du arbejder med dynamiske sprog som JavaScript, hvor du ikke har en statisk klasse, som definerer, hvad objektet indeholder.

Alle objekter har en metode ved navn »hasOwnProperty«, som returnerer »sand«, hvis objektet har en attribut ved det navn. Endvidere kan du få oplyst typen af en værdi ved hjælp operatoren »typeof«. I infoboks »Refleksion« finder du et eksempel på, hvordan det kan bruges.

Nedarvning

I JavaScript betyder nedarvning blot en udvidelse af et eksisterende objekt. Det betyder, at du tager en kopi af et objekt og udvider det. På den måde indeholder det nye objekt de samme nøgler og metoder som det oprindelige, men det er blevet udvidet med det, som du har brug for. Endvidere kan metoderne være blevet ændret (som virtuelle metoder i C++).

Den form for nedarvning omtales i datalogien som differentiel nedarvning, idet nedarvningen sker gennem forskelle (differens) mellem to objekter.
For at kunne følge nedarvningen, har objekter i JavaScript en særlig nøgle med navnet »prototype«. Værdien af den nøgle er faktisk det ob-jekt, som det aktuelle objekt er nedarvet fra. En anden måde at forklare nedarvningen på er at sige, at et objekt bygger videre på en prototy-pe af objektet (moderen).

I infoboks »Brug af prototype« ser du, hvordan du kan bruge prototype til at bygge et objekt op. Eksemplet er tæt på at definere klassen »Person«. Den første funktion er en »constructor«, mens »Person.prototype« udvider klassen med en enkelt metode. Derefter kan du bruge »Person« og oprette objekter.

Næste gang

Både i første og andet afsnit har funktioner været i brug. Men i sidste afsnit vil du se meget mere til dem. Da funktioner er objekter på samme måde som alle andre objekter, kan du bruge funktioner i meget elegante sammenhænge.

Enkle objekter

var kenneth = {
hojde: 173,
alder: 40
};

var svante = {
hojde: 124,
alder: 8
};

console.log(svante.alder);
console.log(kenneth[’alder’]);

svante.alder += 1;
kenneth.alder = 41;
console.log(’Fødselsdag: ’+svante.alder+’/’+kenneth.alder);

kenneth.titel = ’ph.d.’;
console.log(kenneth.titel+’/’+svante.titel);

Slet en nøgle

var kenneth = {
navn: ’Kenneth’,
alder: 40
};

console.log(kenneth.alder);
delete kenneth.alder;
console.log(kenneth.alder);

Komplekse objekter

var familie = {
far: {
navn: ’Kenneth’,
alder: 40
},
mor: {
navn: ’Pia’,
alder: 40
},
barn: [{ navn: ’Svante’, alder: 8}, { navn: ’Svea’, alder: 5 }],
alder: function () {
var i, x;
x = 0;
for (i in this.barn) {
x += this.barn[i].alder;
}
return this.far.alder+this.mor.alder+x;
}
}

console.log(‘Far: ‘+familie.far.alder);
console.log(‘Total: ‘+familie.alder());

Refleksion

var kenneth = {
navn: ’Kenneth’,
alder: 40
};

console.log(kenneth.hasOwnProperty(’navn’));
console.log(kenneth.hasOwnProperty(’hojde’));
console.log(typeof kenneth.navn);


Infoboks – Brug af prototype
function Person(f, e) {
this.fornavn = f;
this.efternavn = e;
};

Person.prototype = {
udskriv: function () {
console.log(this.fornavn+’ ‘+this.efternavn);
}
};

kenneth = new Person;
kenneth.fornavn = ‘Kenneth’;
kenneth.efternavn = ‘Geisshirt’;
kenneth.udskriv();

svante = new Person;
svante.fornavn = ‘Svante’;
svante.efternavn = ‘Geisshirt’;
svante.udskriv();

[themepacific_accordion]
[themepacific_accordion_section title="Fakta"]

Få mere at vide

[/themepacific_accordion_section]
[/themepacific_accordion]