HjemArtiklerOppslag
  • Artikler
  • Introduksjon til Javascript
  • Denne artikkelen inngår i serien Introduksjon til utvikling av nettsider.

    I tidligere artikler har vi sett på hvordan man kan lage statiske nettsider ved hjelp av HTML og CSS. Disse alene er imidlertid ikke tilstrekkelige til å lage dynamisk innhold som responderer på brukerens handlinger. Til det trenger man et programmeringsspråk som kan lytte til hendelser og svare på dem. Til det bruker man Javascript.

    Bakgrunn

    Både HTML og CSS er deklarative språk. De sier hva og hvordan innholdet skal vises. Men de kan ikke endre på innholdet. Til det trenger man støtte fra et språk av en mer imperativ karakter. Derfor har man utviklet Javascript, som kjører i nettleseren og inneholder en rekke verktøy for å lytte til brukerhandlinger, manipulere HTML-treet (dokumentobjektmodellen) og sende spørringer til backenden, for å nevne noe. Det startet som et hjelpemiddel til å utføre helt enkle operasjoner, men har med tiden fått bedre støtte og ytelse i nettleserne, og i dag er det vanlig at hele nettsider er laget med Javascript som grunnlag.

    Da jeg selv lærte å lage nettsider i 2005, gjorde jeg det med backendspråket PHP, som genererte HTML-kode basert på inndata fra brukeren og sendte et ferdig HTML-dokument til nettleseren. Men hvorfor gå veien om backend når man kan gjøre alt i frontend? Noen ganger har man selvfølgelig ikke noe valg. Skal man for eksempel hente data fra en database, må man nødvendigvis innom backend. Men hvis man allerede har alt man trenger av informasjon, og ikke skal endre data som er lagret på tjeneren, er det fullt mulig å gjøre det med Javascript i nettleseren. Som regel er det også raskere, spesielt hvis nettverket er tregt.

    Eksempel

    La oss se på et enkelt eksempel før vi dykker ned i detaljene. Se hva som skjer når du klikker på denne knappen:

    Her burde du ha fått opp en dialog i nettleseren med medlingen "Hei!" og en OK-knapp. Koden ser slik ut:

    I denne koden er kodesnutten alert('Hei!') Javascript-kode, og det er denne som gjør at dialogboksen spretter opp. Siden det står i attributtet onclick, utløses koden idet brukeren klikker på knappen. Attributtet gjør at det legges til en hendelsesovervåkning ("event listener" på engelsk) på knappen. Generelt fungerer alle attributter som starter med on på denne måten, og click er bare én av en lang liste handelser man kan overvåke.

    Hvordan sette det opp

    I likhet med CSS, kan man også skrive Javascript-kode i en egen fil og referere til den fra HTML-koden. Dette gjør man ved å bruke taggen <script>:

    Denne koden peker på filen skript.js i samme mappe som HTML-filen. Filendelsen .js forteller at denne filen skal tolkes som Javascript-kode.

    Denne kodesnutten kan plasseres i <head>-elementet, men ofte plasserer man den heller helt i slutten av <body>-elementet. Det er på grunn av rekkefølgen ting skjer i. Nettleseren leser koden fra topp til bunn, og hvis Javascript-koden kommer før innholdet, vil den også kjøre før innholdet er lastet. Hvis skriptet er avhengig av HTML-elementer på siden, bør det derfor være plassert på slutten.

    Nå lurer du kanskje på hvordan vi kunne skrevet dialogbokseksemplet i en egen fil? Gitt at knappen er den eneste på siden, kunne vi gjort det på denne måten:

    I denne koden finner vi først knappen med koden document.querySelector('button'), og så legger vi til en hendelsesovervåkneng ved hjelp av koden .addEventListener('click', () => alert('Hei!'));. Vi skal se nærmere på denne syntaksen i de påfølgende seksjonene.

    Grunnleggende prinsipper

    Javascript er enda mer omfattende enn HTML og CSS, som vi har sett på i de foregående artiklene. Derfor er det naturligvis ikke mulig å dekke alt i én artikkel, men jeg skal prøve å dekke det mest grunnleggende. Mange av konseptene jeg skal gjennomgå her er svært like i de fleste programmeringsspråk, så hvis du allerede har erfaring med andre programmeringsspråk, vil du nok gjenkjenne mye av det.

    Datatyper

    Når man programmerer, håndterer man flere typer verdier, som tall og tekst. Disse kategoriseres i forskjellige datatyper. I Javascript er de mest grunnleggende datatypene strenger (tekst), tall og boolske verdier. Her er en kjapp gjennomgang av hvordan disse representeres i koden:

    • En streng må ha anførselstegn rundt, enten enkle (') eller doble ("). Eksempel: "Jeg liker is."
    • Et tall skrives rett ut som det er. Dessverre har amerikanerne fått bestemme, og derfor må man bruke punktum og ikke komma hvis tallet har desimaler. Eksempler: 1, 1.2, -1. I Javascript behandles alle tall som flyttall, med unntak av tall som er definert som BigInt, men det skal jeg ikke gå videre inn på her.
    • En boolsk verdi er en verdi som enten er sann eller usann. Den defineres henholdsvis med teksten true eller false.
    Variabler

    En variabel er en beholder for data. I Javascript kan en variabel defineres på tre måter; const, let og var. En variabel som settes med let kan endre sin verdi etterpå, mens en variabel som settes med const ikke kan endres etter at den er satt første gang. var oppfører seg ganske likt som let. Den stammer fra Javascripts yngre dager og er omtrent ikke i bruk lengre, men jeg tenker det er verdt å nevne den siden den forekommer i mange kodeeksempler på andre nettsider.

    Her er et eksempel på hvordan man bruker variabler:

    Denne koden gjør akkurat det samme som forrige eksempel, bare at de forskjellige komponentene er plassert i variabler. I dette tilfellet kan man argumentere for at bruken av variabler er unødvendig siden hver variabel kun brukes én gang. Men se hvor mye mer lesbar koden blir. Kodelinjen knapp.addEventListener('click', visMelding) forklarer nærmest seg selv uten at man trenger å se lenge på den. Når man jobber på store prosjekter med titusener av kodelinjer, er det helt avgjørende at koden er lesbar og forståelig, og det oppnår man nettopp ved å dele den i variabler med forklarende navn.

    La oss ta en titt på et annet eksempel:

    Gitt at HTML-dokumentet ganske enkelt er en knapp med tallet 0, blir resultatet slik - legg merke til at tallet øker hver gang man klikker på knappen:

    økAntallKlikk er en funksjon, i likhet med visMelding i forrige eksempel. Vi skal se nærmere på funksjoner i neste seksjon. Det jeg vil trekke frem her er det som skjer inni funksjonen, og spesielt kodesnutten antallKikk++. Det som skjer her er at innholdet i variabelen antallKlikk øker med én. Dette forutsetter to ting, nemlig at innholdet er et tall og at variabelen er foranderlig. Derfor er antallKlikk definert med let. Hadde den vært definert med const, ville koden feilet.

    Neste linje, knapp.innerHTML = antallKlikk, sørger for at tallet i knappen blir oppdatert med den nyeste verdien av antallKlikk. Siden funksjonen kjører hver gang brukeren klikker på knappen, resulterer dette i en knapp som viser hvor mange ganger den har blitt klikket på.

    Nå spør du kanskje; hvorfor gjøre ting vanskelig for seg selv ved å bruke const? Hva om man endrer mening og finner ut at man vil endre på innholdet i variabelen? Da har du rett i at koden vil fungere like bra om man erstatter alle const med let. Men kodekvalitet handler i stor grad om å sette restriksjoner for seg selv. Et kodeverktøy vil da kunne oppdage at man har gjort noe som ikke er i henhold til det som var tiltenkt i utgangspunktet, og på den måten vil man oppdage feil med en gang, i stedet for at de blir liggende i koden og skaper følgefeil. Bruk derfor alltid const hvis ikke du vet at variabelen må være foranderlig.

    Funksjoner

    En funksjon er en samling av kodelinjer som utfører en bestemt oppgave. Vi har sett noen eksempler på funksjoner allerede. En funksjon erklæres ved hjelp av nøkkelordet function på denne måten:

    En fordel med funksjoner er at de kan brukes gjentatte ganger, så hvis man trenger den samme koden flere steder, er det bare å plassere den i en funksjon og kalle funksjonen der den trengs. Det gjøres ved å skrive navnet på funksjonen etterfulgt av parentes:

    En funksjon kan også ta imot parametre. Det er variabler som defineres idet funksjonen kalles. Her er et eksempel på en funksjon med to parametre:

    Denne funksjonen har også en returverdi, altså et resultat av operasjonen den utfører. I dette tilfellet er det summen av de to tallene som den tar imot. Denne kan man for eksempel plassere i en ny variabel:

    I et av de første eksemplene i denne artikkelen la du kanskje merke til at funksjonen var skrevet på en annen måte;

    Mens definisjonen med function er en erklæring, er dette et uttrykk. Det som skjer rent teknisk når man gjør det på denne måten er at man oppretter en variabel som peker på en anonym funksjon, altså en funksjon som ikke er erklært. Man er derfor nødt til å bruke variabelnavnet når man skal kalle funksjonen, og det gjør man på akkurat samme måte som når man kaller en erklært funksjon.

    Fordelen med en erklært funksjon er at den kan kalles fra kode som kommer foran selve erklæringskoden. Programmet som tolker koden vil nemlig først gå over koden og registrere alle funksjonserklæringer. Derfor kan man skrive erklæringene lengre ned i koden, noe som ofte vil gjøre den mer lesbar for mennesker. Variabler, derimot, må være definert før de kan tas i bruk.

    Betingelser

    En betingelse er en kodeblokk som utføres kun hvis en gitt betingelse er sann. I Javascript skrives dette med nøkkelordene if, else if og else. Her er et eksempel som bygger videre på eksemplet med knappen som viser antall klikk:

    Her har vi lagt til en betingelse som sjekker om antallet klikk er mer enn to. I så fall skal knappens bakgrunnsfarge bli gul. Ellers skal bakgrunnen bli lyseblå. Du kan se resultatet her:

    Løkker

    En løkke er en kodeblokk som gjentas enten et gitt antall ganger, eller så lenge en gitt betingelse er sann.

    Telleløkke

    Når man på forhånd har informasjon om hvor mange ganger en kode skal kjøres, er det mest hensiktsmessig å bruke en telleløkke. Det gjør man ved hjelp av nøkkelordet for. So for eksempel på denne koden:

    Hver gang koden kjøres, blir det lagt til et avsnitt med teksten "Tekst nummer [i]", hvor [i] er tallet i variabelen i. Hvis man kjører denne koden i et tomt HTML-dokument, blir resultatet slik:

    Som du kan se, har koden kjørt tre ganger, og i er først 1, for så å øke med én for hver gang. Alt dette bestemmes av denne kodesnutten: (let i = 1; i <= 3; i++). Denne er satt sammen av tre uttrykk, som er adskilt med semikolon.

    1. Det første uttrykket kjøres i starten, så det er her man må definere variabler som skal brukes. I eksempelkoden, let i = 1, blir variabelen i initialisert med verdien 1.
    2. Det andre uttrykket er en betingelse. Denne sjekkes før hver iterasjon, og løkken avsluttes idet denne blir usann. Koden i <= 3 i eksemplet bestemmer at løkken skal kjøres så lenge verdien av i er mindre eller lik 3.
    3. Det tredje uttrykket kjøres etter hver iterasjon. Det vanligste å gjøre her er å øke iterasjonsvariabelen med én, og det er akkurat det eksempelkoden i++ gjør.
    Tilstandsløkke

    En tilstandsløkke kjøres så lenge en gitt betingelse er sann. Det gjøres ved hjelp av nøkkelordet while. Mye er likt som i en telleløkke, men en tilstandsløkke inneholder kun betingelsesuttrykket på den første linjen. Alt som kan skrives som en telleløkke kan imidlertid også skrives som en tilstandsløkke. La oss se på forrige eksempel. Hvis vi skulle skrevet denne koden som en tilstandsløkke, ville den blitt slik:

    Dette gir nøyaktig samme resultat. En tilstandsløkke er mer hensiktsmessig når man ikke kan forutse resultatet av betingelsen, for eksempel når den avhenger av inndata fra brukeren.

    Objekter og tabeller

    Et objekt er en samling av egenskaper og metoder. Egenskapene er variabler som er knyttet til objektet, mens metodene er funksjoner som er knyttet til objektet. I Javascript skrives et objekt med krøllparenteser:

    Referere til egenskaper

    Det er flere måter å referere til objektegenskaper på. Den ene er ved hjelp av punktum:

    Dette metoden har vi allerede brukt i mange av eksemplene, for eksempel i knapp.innerHTML. innerHTML er nemlig en egenskap på objektet knapp.

    En annen måte å referere til objektegenskaper på er ved hjelp av firkantparenteser:

    Denne metoden er nyttig når egenskapene har spesialtegn i navnet eller når navnet på egenskapen er lagret i en variabel. For eksempel:

    En siste metode er destrukturering. Den er særegen for Javascript og ser slikt ut:

    Her oppretter vi nye variabel med samme navn som egenskapene vi vil hente ut. Denne kan gjøre koden litt kortere hvis egenskapene brukes flere steder.

    Tabeller

    En tabell er en liste med verdier, ofte omtalt med det engelske begrepet "array", som også er nøkkelordet som brukes i koden. En tabell kan defineres på denne måten:

    I Javascript er en tabell bare en spesiell form for et objekt, hvor nøklene er tall i stedet for strenger. Nøklene starter på null og øker med én for hvert element i listen. For å referere til et element, kan man bruke firkantparenteser på samme måte som på et vanlig objekt. I eksemplet over vil farger[0] være "rød", farger[1] være "grønn" og farger[2] være "blå".

    Klasser

    En klasse er en mal for å lage objekter. I Javascript defineres en klasse med nøkkelordet class. Her er et eksempel på en klasse for objektet fra forrige seksjon:

    Hvis en klasse er avhengig av parametre, må den ha en funskjon som heter constructor. Denne blir kalt idet klassen oppretter et objekt. I eksemplet ser vi at denne funksjonen setter to egenskaper på objektet this. this er en reservert variabel. Det vil si at den settes automatisk og at man ikke kan lage variabler med det navnet. I en klasse brukes den til å peke på objektet som klassen lager.

    Et objekt instansieres fra en klasse ved help av nøkkelordet new, navnet på klassen og inndataen til constructor-funksjonen. For å lage et objekt fra klassen over, kan man gjøre slik:

    Hvis man nå peker på ola.navn, får man "Ola Nordmann".

    Dette kan se ut som en komplisert måte å opprette objekter på, og for enkle objekter som dette kan det være like greit å bare definere det direkte, som vist under objekter og tabeller, uten å gå omveien om en klasse. Skal man imidlertid også ha komplekse funksjoner på et objekt, er det som regel mer oversiktlig å bruke en klasse. Funksjoner i klasser kalles ofte metoder. Her er et eksempel på den samme klassen som over, men med en metode for å øke alder med ett år:

    Den siste linjen i dette eksemplet inneholder for øvrig en funskjon som er svært nyttig for læring og feilsøking, nemlig console.log. Den skriver ut en verdi i konsollen, som man kan se i utviklerverktøyet.

    Klasser har mange egenskaper ut over dette som jeg ikke skal gå inn på i denne artikkelen. Blant annet kan man bruke abstrakte klasser til å lage maler for klasser, og man kan bruke nøkkelordet extends til å lage en klasse basert på en annen. Ikke minst er også muligheten til å lage private variabler og metoder svært nyttig for å holde koden ryddig. Alt dette faller inn under en paradigme som kalles objektorientert programmering.

    Dokumentobjektmodellen

    Javascript er laget spesielt for å brukes sammen med HTML-dokumenter i nettleseren, og noe av det viktigste som skiller Javascript fra andre programmeringsspråk er at det har innebygget funksjonalitet for å manipulere innholdet på en nettside og samhandle med nettleseren på andre måter. Vi har allerede vært innom flere eksempler på dette i denne artikkelen. Den reserverte variabelen document tilgang til alle mulige egenskaper ved dokumentet. Ved hjelp av metoden document.querySelector kan man få tilgang til et hvilket som helst HTML-element ved å bruke selektorer på samme måte som i CSS - se seksjonen om selektorer i forrige artikkel. Metoden document.createElement kan brukes til å opprette et HTML-element, og element.appendChild kan brukes til å legge til elementet som et barn av elementet i variabelen element, som må være en instans av klassen HTMLElement. Man kan lage fullstendige nettsider på denne måten, nesten uten en eneste linje HTML. Rammeverk som React, som jeg skal skrive mer om i fremtidige artikler, gjør akkurat det.

    Alle disse funksjonene er den del av det som kalles dokumentobjektmodellen, forkortet dom. Den går ut på at HTML-koden blir oversatt til en objektstruktur som gjør at den kan behandles av Javascript, for så å oversettes tilbake igjen til HTML.

    Dokumentobjektmodellen tillater også å lage egendefinerte HTML-komponenter, såkalte webkomponenter. Dette er noe jeg ikke har skrevet om så langt i artikkelen, men det er et konsept som er på fremmarsj og som blir stadig mer utbredt i bruk. Jeg planlegger å skrive mer om det i fremtidige artikler.

    Javascript-baserte språk

    I denne artikkelserien har jeg dekket kode som man bare trenger en nettleser for å kunne kjøre. Men Javascript danner også grunnlaget for flere populære verktøy og språk som krever at man installerer andre programmer.

    Node

    Node er et kjøretidsmiljø som tillater at man kjører Javascript også på tjenersiden. Koden vi har sett på til nå kjører på klientsiden, det vil si at den tolkes og kjøres av nettleseren. Hvis man skal lagre data eller hente data som krever spesiell tilgang, er man nødt til å tilrettelegge for dette på tjenersiden. Dette er kode som kjører før noe blir sendt til brukerens maskin og som derfor ikke er synlig for brukeren. Eksempler på språk som brukes her er Java, PHP og Python. Node gjør det altså også mulig å bruke Javascript. En stor fordel med det er at man ikke trenger å beherske to forskjellige programmeringsspråk. En annen er at man kan ha et bibliotek med felles kode som brukes på begge sider, noe som er nyttig i forbindelse med validering. Node kan lastes ned fra Nodes nettside.

    Typescript

    Typescript er et supersett av Javascript. Det vil si at all Javascript-kode også er gyldig som Typescript, men Typescript tilfører også tilleggsfunksjonalitet. Denne utgjøres av muligheten til å definere egne datatyper og å spesifisere hvilken datatype en variabel kan ha. Det gjør det lettere å for mennesker å tolke koden og det hindrer at man gjør slurvefeil. I et oppegående kodeverktøy kan man få løpende validering mens man skriver koden, noe som gjør at man oppdager feil med en gang. Prøver man å kjøre kode med typefeil, vil man (i de fleste tilfeller) få en beskrivende feilmelding i kommandolinjeverktøyet.

    Typescript fungerer på den måten at koden først blir konvertert til Javascript, som igjen kan kjøres i en hvilken som helst nettleser. Man kan altså fint bruke Typescript til å lage nettsider uten at det krever at brukerne installerer noe ekstra. Det er det kun utviklerne som skriver koden som må gjøre.

    For å kunne lage Typescript-programmer, må man ha Node installert (se forrige seksjon). I tillegg må man ha en pakkebehandler som NPM, Yarn eller PNPM. Se Typescripts offisielle nettside for en grundig veiledning.

    React

    React er et populært rammeverk for å lage brukergrensesnitt. I likhet med Typescript er det et språk som blir konvertert til vanlig Javascript før det distribueres til brukeren. Typescript og React fungerer likevel helt fint sammen. React tilfører JSX, som er en syntaks som lar utikleren skrive HTML-liknende kode direkte i Javascript-koden. Det gjør at koden blir mer deklarativ, noe som gir mening når man lager et brukergrensesnitt. React har også elegante verktøy for tilstandshåndtering.

    Det finnes et rikt utvalg biblioteker som er basert på React, noe som har vært med på å holde rammeverket aktuelt i godt over et tiår. Blant annet er mange designsystemer laget med React.

    For å ta i bruk React, er det også nødvendig å ha en pakkebehandler. Videre er det flere veier å velge mellom ut fra hva man ønsker. Dette er det mer informasjon om på Reacts nettside. Selv har jeg god erfaring med Vite og deres React-utvidelse.

    Alternativer til React er eksempelvis Angular, Vue og Svelte.

    Nyttige lenker

    I likhet med HTML og CSS, har både W3schhols og MDN mer fullstendige sider om Javascript:

    • W3schools' Javascript-sider
    • MDNs Javascript-sider

    Ellers er JSFiddle et fint verkøy for eksperimentering med Javascript, HTML og CSS direkte i nettleseren.

    Veien videre

    Denne artikkelen markerer slutten på artikkelserien. Vi har nå sett på de tre kodespråkene som brukes på klientsiden av en nettside. Hvis du ønsker å lære mer om andre aspekter ved utvikling av nettsider, og det håper jeg du gjør, er det flere veier å gå. For eksempel kan det være naturlig å se på backendutvikling. Da er det mange programmeringsspråk å velge mellom, men hvis du liker Javascript, kan du jo godt bruke Node. I forbindelse med backendutviklig kan det også være nyttig å sette seg inn i databaser, for eksempel PostgreSQL. En annen aktuell retning er å se mer på frontendteknologi. Da kan Typescript og React være aktuelle teknologier.

    © Tomas Engebretsen | Bygget med Tomas' designsystem.