Moduler - Utvikling (IM-ITK vg2) - NDLA

Hopp til innhold
Fagartikkel

Moduler

Vi har ofte behov for å importere data og funksjoner fra kodebiblioteker når vi skriver JavaScript. Vi kan også lage egne moduler som kan importeres og eksporteres mellom JavaScript-filer.

Det kan ofte være fordelaktig å dele opp JavaScript-koden i flere filer. Det kan være at vi ønsker å skille ut variabler som skal være enkle å endre på, eller at vi har funksjoner eller klasser som skal brukes av flere websider eller programmer.

Hvis du har brukt Firebase, MySQL eller React på en webside, har du sikkert sett nøkkelordet import øverst i koden, og at scriptet i HTML-fila har type="module" i script-taggen. Da er det brukt moduler.

Lag din egen modul

Nå skal du lage din egen enkle modul. Først må du lage ei .js-fil. Kall fila navn.js, og legg inn denne koden:

navn.js
1let navn = "Kim";
2
3export { navn };

Leg merke til at vi bruker krøllparentes rundt variabelnavnene som skal eksporteres.

Lag så ei HTML-fil i samme mappe som du kaller index.html. Legg inn de nødvendige taggene du trenger for å lage en webside. (I VS Code: skriv ! (utropstegn) og trykk enter.) Nederst i <body>-taggen skriver du denne koden:

index.html
1<script type="module">
2
3import { navn } from "./navn.js";
4
5//Skriver ut verdien til variabelen navn
6console.log(navn);
7
8</script>

Hvis du åpner index.html i nettleseren og åpner inspiser-verktøyet, vil du se at Kim er skrevet ut i konsollen. Prøv å endre navnet i navn.js til noe annet, og oppdater siden. Da vil du se at det nye navnet skrives ut.

Får du feilmelding i konsollen?

Hvis du åpner HTML-fila fra harddisken (fra "Utforsker" eller "Finder"), kan du få denne feilmeldinga:

"Access to script at 'file:///(...)/navn.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https."

Dette er på grunn av en begrensning i Chrome-nettleseren som gjør at nettsider bare kan referere til filer på webservere og ikke filer på en harddisk. For å løse problemet må du starte en lokal webserver på maskinen din. Den enkleste måten å gjøre det på er å installere tillegget Live Preview eller Live Server i Visual Studio Code.

Eksportere og importere flere variabler

En modul kan inneholde flere datatyper. Hvis vi tar utgangspunkt i navn.js fra forrige eksempel, kan vi legge til en variabel for alder. Da blir koden slik:

navn.js
1let navn = "Kim";
2let alder = 17;
3
4export { navn, alder };

Vi kan nå importere begge variablene i index.html, slik:

index.html
1<script type="module">
2
3import { navn, alder } from "./navn.js";
4
5console.log(`${navn} er ${alder} år gammel`);
6
7</script>

Konsollen i nettleseren vil da vise Kim er 17 år gammel.

Definere klasser i egne moduler

Det er ikke bare variabler som kan eksporteres og importeres. Vi kan eksportere alle typer data, som lister, objekter og klasser.

Det kan være ryddig å skille ut klasser i egne moduler. Da kan du importere klassene og bare ha koden for å opprette objekter i scriptet til nettsiden. Hvis vi tar utgangspunkt i eksempelet om biler, kan vi opprette fila biler.js:

biler.js
1class Bil {
2
3  constructor(bilmerke, modell, farge, 
4    toppfart, fart) {
5    this.bilmerke = bilmerke,
6    this.modell = modell,
7    this.farge = farge,
8    this.toppfart = toppfart,
9    this.fart = fart
10  }
11  
12  presenter() {
13    return `Denne bilen er en ${this.farge} ${this.bilmerke} ${this.modell}, \
14med en toppfart på ${this.toppfart} km/h. \
15Akkurat nå har den en fart på ${this.fart} km/h.`
16  }
17  
18  giGass() {
19    if (this.fart + 2 <= this.toppfart) {
20      this.fart = this.fart + 2;
21    }
22  }
23  
24}
25    
26class Elbil extends Bil {
27
28  constructor(bilmerke, modell, farge, toppfart, 
29    fart, batterikapasitet, batteristatus) {
30  
31    super(bilmerke, modell, farge, toppfart, fart);
32    this.batterikapasitet = batterikapasitet;
33    this.batteristatus = batteristatus;
34    
35  }
36  
37  presenter() {
38      return `Denne bilen er en ${this.farge} ${this.bilmerke} ${this.modell}, \
39med en toppfart på ${this.toppfart} km/h og batterikapasitet på ${this.batterikapasitet} kWh. \
40Akkurat nå har den en fart på ${this.fart} km/h, og batteriet er ladet ${this.batteristatus}%.`
41  }
42  
43  lading() {
44    this.batteristatus = this.batteristatus + 10;
45  }
46  
47}
48
49export { Bil, Elbil };    

Da kan vi bruke disse klassene i flere andre filer ved å importere klassene i scriptet.

index.html
1<script type="module">
2
3import {Bil, Elbil} from "./biler.js";
4
5const biler = [];
6
7biler.push( new Bil("Porsche", "911", "svart", 290, 0) );                  //biler[0]
8biler.push( new Bil("Ferrari", "F8 Spider", "rød", 340, 0) );              //biler[1]
9biler.push( new Bil("Ford", "Mustang Mach 1", "blå", 270, 0) );            //biler[2]
10biler.push( new Elbil("Ford", "Mustang Mach e", "grå", 180, 0, 68, 100) ); //biler[3]
11biler.push( new Elbil("Tesla", "Model 3", "hvit", 260, 0, 50, 70) );       //biler[4]
12  
13for(let i of biler){
14  console.log(i.presenter());
15}
16  
17</script>

Bruke moduler for å skille ut databasekobling

Hvis vi bruker en databasekobling, kan vi skille ut koden vi bruker for å koble til databasen i ei egen fil. Da blir koden vår ryddigere, og vi slipper å lime inn denne koden i alle filene der vi skal bruke databasen. Hvis du for eksempel skal bruke Firebase, kan du lage en modul med databasekonfigurasjonen og eksportere databaseobjektet. I alle andre filer som bruker databasen, trenger du dermed bare importere denne modulen. Denne koden kan se slik ut:

firebaseconfig.js
1// Importerer intitalizApp fra Firebase-app SDK
2import { initializeApp } from "https://www.gstatic.com/firebasejs/9.6.3/firebase-app.js";
3// Importerer getFirestore fra Firebase-Firestore SDK 
4import { getFirestore } from "https://www.gstatic.com/firebasejs/9.6.3/firebase-firestore.js"
5
6// Konfigurerer Firebase
7const firebaseConfig = {
8  apiKey: "_API_KEY_",
9  authDomain: "_PROJECT_ID_.firebaseapp.com",
10  projectId: "_PROJECT_ID_",
11  storageBucket: "_PROJECT_ID_.appspot.com",
12  messagingSenderId: "_SENDER_ID_",
13  appId: "_APP_ID_",
14};
15
16// Starter opp Firebase med den angitte konfigurasjonen
17const app = initializeApp(firebaseConfig);
18// Henter ut referanse til Firestore-databasen
19const db = getFirestore();
20
21// Eksporterer databasen
22export { db };

Når du nå skal bruke Firestore-databasen på nettsiden din, trenger du bare importere db fra firebaseconfig.js, slik:

index.html
1<script type="module">
2// Importerer databasen med Firebase-konfigurasjonen
3import { db } from "./firebaseconfig.js";
4
5// Importerer Firebase-funksjonene vi bruker i dette scriptet 
6// fra Firebase-Firestore SDK
7import { setDoc, doc } from "https://www.gstatic.com/firebasejs/9.6.3/firebase-firestore.js";
8
9// Lager et nytt dokument i samlinga "elever"
10await setDoc(
11  doc(db, "elever", "nilja"), {
12    fornavn: "Jakob",
13    etternavn: "Nilsen",
14    epost: "jakob@nilsen.net"
15  });
16
17</script>

Relatert innhold

Fagstoff
Objekter og klasser

Objekter er en datatype i programmering der vi kan samle flere biter informasjon i en og samme variabel.

Fagstoff
Oppsett av Firebase og Cloud Firestore

I denne guiden vil du lære et basisoppsett som du skal bruke videre i modulen "Lage en dynamisk webside med databasekobling i Firebase Cloud Firestore".

Skrevet av Karl Arne Dalsaune.
Sist faglig oppdatert 23.06.2022