Eksamenssett logo
eksamenssett.noTren målrettet
  • Ungdomsskole/VGS
  • Høyskole
  • Ressurser
  • Skolenyttig
  • Forum
eksamenssett.noTren målrettet

Komplett samling av eksamensoppgaver og løsninger for norsk skole.

Om ossFAQPersonvernVilkårAngrerettKontakt

© 2025 Eksamenssett.no · Alle rettigheter forbeholdt

Innholdet er utviklet med AI-verktøy og kvalitetssikres kontinuerlig. Slik jobber vi med kvalitet →

Eksamenssett.no eies og drives av Studenthjelp Privatundervisning AS

Eksamenssett logo
eksamenssett.noTren målrettet
  • Ungdomsskole/VGS
  • Høyskole
  • Ressurser
  • Skolenyttig
  • Forum
eksamenssett.noTren målrettet

Komplett samling av eksamensoppgaver og løsninger for norsk skole.

Om ossFAQPersonvernVilkårAngrerettKontakt

© 2025 Eksamenssett.no · Alle rettigheter forbeholdt

Innholdet er utviklet med AI-verktøy og kvalitetssikres kontinuerlig. Slik jobber vi med kvalitet →

Eksamenssett.no eies og drives av Studenthjelp Privatundervisning AS

Eksamenssett logo
eksamenssett.noTren målrettet
  • Ungdomsskole/VGS
  • Høyskole
  • Ressurser
  • Skolenyttig
  • Forum
eksamenssett.noTren målrettet

Komplett samling av eksamensoppgaver og løsninger for norsk skole.

Om ossFAQPersonvernVilkårAngrerettKontakt

© 2025 Eksamenssett.no · Alle rettigheter forbeholdt

Innholdet er utviklet med AI-verktøy og kvalitetssikres kontinuerlig. Slik jobber vi med kvalitet →

Eksamenssett.no eies og drives av Studenthjelp Privatundervisning AS

Eksamenssett logo
eksamenssett.noTren målrettet
  • Ungdomsskole/VGS
  • Høyskole
  • Ressurser
  • Skolenyttig
  • Forum
eksamenssett.noTren målrettet

Komplett samling av eksamensoppgaver og løsninger for norsk skole.

Om ossFAQPersonvernVilkårAngrerettKontakt

© 2025 Eksamenssett.no · Alle rettigheter forbeholdt

Innholdet er utviklet med AI-verktøy og kvalitetssikres kontinuerlig. Slik jobber vi med kvalitet →

Eksamenssett.no eies og drives av Studenthjelp Privatundervisning AS

Eksamenssett logo
eksamenssett.noTren målrettet
  • Ungdomsskole/VGS
  • Høyskole
  • Ressurser
  • Skolenyttig
  • Forum
  1. Hjem
  2. Informasjonsteknologi
  3. IT 2 – JavaScript
  4. Løsning Vår 2025
VG3

Løsningsforslag Informasjonsteknologi IT 2 – JavaScriptVår 2025

Se eksamensoppgaven
Høst 2024Eldre
Om løsningsforslaget: Dette er et veiledende løsningsforslag laget av eksamenssett.no for REA3049-JS Vår 2025. Vi gir korrekte svar på flervalgsoppgavene (1–4) med begrunnelse, fullstendig JavaScript-kode for programmeringsoppgavene (5b, 6, 8, 9), og eksempelsvar på drøftingsoppgaven (7).

Løsningsforslag – IT 2 JavaScript Vår 2025

Eksamen: REA3049-JS | Semester: Vår 2025 | Tema: Pseudokode, OOP, Caesar-chiffer, bibliotek, friluftsdatasett, skogbrann-simulering

Oppgave 1 – Pseudokode (TrommeLom)

Oppgaven: Hva blir resultatet av sjekkTall(6)? Tall delelig på både 2 og 3 erstattes med "TrommeLom", bare 2 med "Tromm", bare 3 med "Lom".
Riktig svar: 1 Tromm Lom Tromm 5 TrommeLom
ii % 2i % 3Hvilken gren?Lagt til
111else"1 "
202else if i%2==0"Tromm "
310else if i%3==0"Lom "
401else if i%2==0"Tromm "
512else"5 "
600første if (begge)"TrommeLom "

En variant av FizzBuzz-problemet. Sammensetningen blir "1 Tromm Lom Tromm 5 TrommeLom".

Oppgave 2 – Klasserelasjoner

Oppgaven: Objekter av en klasse eksisterer bare innenfor objekter av en annen klasse. Hvilken relasjon?
Riktig svar: komposisjon

Komposisjon er en sterk «inneholder»-relasjon der den indre delens livssyklus er bundet til den ytre helheten. Skiller seg fra aggregering (svakere — delene kan eksistere alene), assosiasjon (løs «vet om»), generalisering (arv) og avhengighet (midlertidig bruk).

Oppgave 3 – OOP-prinsipp: samme metodenavn i super- og subklasse

Riktig svar: polymorfisme

Polymorfisme («mange former») betyr at samme metodenavn kan ha forskjellig oppførsel avhengig av objektets faktiske type. I JavaScript skjer dette via prototypekjeden: obj.metode() ser først etter metode på objektet selv, deretter oppover prototypekjeden.

Oppgave 4 – OOP-prinsipp: skjule interne detaljer

Riktig svar: innkapsling

Innkapsling skjuler implementasjonen og eksponerer kun et grensesnitt utad. I moderne JavaScript bruker man #-prefiks for private felter (#felt) eller closures for å oppnå reell innkapsling. Innkapsling gjør at implementasjonen kan endres uten å bryte koden som bruker objektet.

Oppgave 5 – Caesar-chiffer

Oppgave 5a – Forklaring

Algoritmen er et enkelt Caesar-chiffer tilpasset det norske alfabetet. Den forskyver hver bokstav n plasser framover i et alfabet på 29 tegn (a–å). Bokstaver som ikke er bokstaver — mellomrom, tall, tegnsetting — beholdes uendret. Manipuleringen finner posisjonen til hver bokstav og bruker modulo 29 ((posisjon + n) % 29) slik at vi pakker rundt når vi går forbi å. Med n = 3 blir a → d, og å → c.

Oppgave 5b – Implementasjon i JavaScript

// oppgave5b.mjs — Caesar-chiffer for norsk alfabet

const ALFABET_SMA = "abcdefghijklmnopqrstuvwxyzæøå";
const ALFABET_STORE = ALFABET_SMA.toUpperCase();
const ALFABET_LENGDE = ALFABET_SMA.length; // 29

function manipulerBokstav(bokstav, n) {
  const idxSma = ALFABET_SMA.indexOf(bokstav);
  if (idxSma !== -1) {
    const nyPos = ((idxSma + n) % ALFABET_LENGDE + ALFABET_LENGDE) % ALFABET_LENGDE;
    return ALFABET_SMA[nyPos];
  }
  const idxStor = ALFABET_STORE.indexOf(bokstav);
  if (idxStor !== -1) {
    const nyPos = ((idxStor + n) % ALFABET_LENGDE + ALFABET_LENGDE) % ALFABET_LENGDE;
    return ALFABET_STORE[nyPos];
  }
  return bokstav; // tall, mellomrom, tegnsetting beholdes
}

export function behandleTekst(tekst, n) {
  return [...tekst].map(b => manipulerBokstav(b, n)).join("");
}

// CLI-bruk: node oppgave5b.mjs "Hei på deg" 3
if (import.meta.url === `file://${process.argv[1]}`) {
  const [, , tekst, nStr] = process.argv;
  const n = parseInt(nStr, 10);
  if (Number.isNaN(n)) {
    console.error("Bruk: node oppgave5b.mjs <tekst> <n>");
    process.exit(1);
  }
  const resultat = behandleTekst(tekst, n);
  console.log(`Original:  ${tekst}`);
  console.log(`Kryptert:  ${resultat}`);
  console.log(`Verifisering: ${behandleTekst(resultat, -n)}`);
}
Eksempel: node oppgave5b.mjs "Hei på deg" 3 → "Khl rb gho". Den dobbelte modulo-trikset ((x % m) + m) % m er nødvendig for å håndtere negative n-verdier korrekt — JavaScripts % kan returnere negativt resultat.

Oppgave 6 – Bibliotek (Bok og Låner)

Oppgave 6a – Klassediagram

Toveis assosiasjon: en Bok kan være utlånt til én Låner (0..1), og en Låner kan ha flere Bok-objekter (0..*). Begge eksisterer uavhengig av hverandre.

+----------------------+              +-------------------------+
|        Bok           |              |        Laner            |
+----------------------+              +-------------------------+
| - tittel: string     |    0..*      | - lanerId: number       |
| - forfatter: string  |<-------------| - lanteBoker: Bok[]     |
| - utlant: Laner|null |   0..1       +-------------------------+
+----------------------+              | + lanBok(b: Bok)        |
| + visInfo()          |              | + leverTilbakeBok(b)    |
+----------------------+              +-------------------------+

Oppgave 6b – Implementasjon i JavaScript

// bibliotek.mjs

export class BibliotekFeil extends Error {
  constructor(melding) {
    super(melding);
    this.name = "BibliotekFeil";
  }
}

export class Bok {
  constructor(tittel, forfatter) {
    this.tittel = tittel;
    this.forfatter = forfatter;
    this.utlant = null;
  }
  visInfo() {
    const status = this.utlant
      ? `utlånt til ${this.utlant.navn} (ID ${this.utlant.lanerId})`
      : "tilgjengelig";
    console.log(`'${this.tittel}' av ${this.forfatter} — ${status}`);
  }
}

export class Laner {
  constructor(lanerId, navn) {
    this.lanerId = lanerId;
    this.navn = navn;
    this.lanteBoker = [];
  }
  lanBok(bok) {
    if (bok.utlant !== null) {
      throw new BibliotekFeil(
        `'${bok.tittel}' er allerede utlånt til ${bok.utlant.navn}.`
      );
    }
    bok.utlant = this;
    this.lanteBoker.push(bok);
  }
  leverTilbakeBok(bok) {
    const idx = this.lanteBoker.indexOf(bok);
    if (idx === -1) {
      throw new BibliotekFeil(`${this.navn} har ikke lånt '${bok.tittel}'.`);
    }
    bok.utlant = null;
    this.lanteBoker.splice(idx, 1);
  }
}

Oppgave 6c – Testprogram

// test_bibliotek.mjs
import { Bok, Laner, BibliotekFeil } from "./bibliotek.mjs";

const bok1 = new Bok("Sofies verden", "Jostein Gaarder");
const bok2 = new Bok("Naiv. Super.", "Erlend Loe");
const bok3 = new Bok("Beatles", "Lars Saabye Christensen");
const emma = new Laner(1, "Emma");
const ola = new Laner(2, "Ola");

// 1) Lån ut
emma.lanBok(bok1);
emma.lanBok(bok2);
bok1.visInfo();
console.assert(emma.lanteBoker.includes(bok1));
console.assert(bok1.utlant === emma);

// 2) Lever tilbake
emma.leverTilbakeBok(bok1);
bok1.visInfo();
console.assert(!emma.lanteBoker.includes(bok1));
console.assert(bok1.utlant === null);

// 3) Forsøk på å låne ut bok som allerede er utlånt
ola.lanBok(bok3);
try {
  emma.lanBok(bok3);
  throw new Error("Skulle kastet BibliotekFeil");
} catch (e) {
  if (e instanceof BibliotekFeil) console.log(`OK — fanget: ${e.message}`);
  else throw e;
}

// 4) Lever tilbake bok som ikke er lånt
try {
  emma.leverTilbakeBok(bok3);
} catch (e) {
  if (e instanceof BibliotekFeil) console.log(`OK — fanget: ${e.message}`);
}

console.log("Alle tester passert.");

Oppgave 6d – Feilhåndtering

Egendefinert BibliotekFeil-klasse arver fra Error. Kallende kode kan bruke instanceof BibliotekFeil for å skille bibliotek-feil fra andre feil. Begge feilstier er testet i 6c.

Oppgave 7 – VR og sosial angst (etiske dilemmaer)

VR-baserte behandlingsverktøy gir nye muligheter for trygg eksponering, men reiser etiske spørsmål. Jeg vil drøfte to sentrale dilemmaer: (1) personvern og biometri, og (2) overføringsverdi versus teknologiavhengighet.

Dilemma 1: Personvern og biometri. VR-headset registrerer mer enn bilde og lyd: blikkretning, hodebevegelser, hudkonduktans, puls. For en ungdom med sosial angst innebærer dette innsamling av sensitive data om frykt-respons og kroppslige reaksjoner. Etter GDPR (artikkel 9) er dette spesielt beskyttede helseopplysninger. Hvem eier dataene — sykehuset, leverandøren, eller Emma? Brukes de bare til behandling, eller også til å trene maskinlæringsmodeller? At Emma er mindreårig (16) skjerper kravet til reelt informert samtykke. Et argument for bruk er at behandlingen kan hjelpe henne ut av en alvorlig lidelse; mot taler at innsamlede biometriske data kan følge henne resten av livet hvis de lekker.

Dilemma 2: Overføringsverdi versus teknologiavhengighet. Casen sier at Emma «føler seg tryggere i virtuelle situasjoner, men er usikker på hvordan hun vil håndtere virkelige presentasjoner». Forskning på eksponeringsterapi viser at habituering må generaliseres til reelle situasjoner. Hvis Emma blir avhengig av VR-rommet, kan teknologien forsterke unngåelsesatferd — det motsatte av målet. Etisk er det viktig at behandlingen designes med tydelig overgang til reell øvelse, og at framgang måles i hverdagslige situasjoner.

Konklusjon: VR er etisk forsvarlig dersom det kombineres med streng datakontroll, reell overføring til ekte situasjoner, og likeverdig tilgang. Uten disse rammene risikerer man både personverninngrep og at teknologien blir et komfortabelt unngåelsesrom.

Oppgave 8 – Friluftsaktiviteter (datasett)

// oppgave8.mjs — friluftsaktiviteter (Node.js + Chart.js for diagram)
// pip install ikke nødvendig; vi bruker innebygd fs og csv-parsing.
import { readFileSync } from "node:fs";
import readline from "node:readline/promises";
import { stdin as input, stdout as output } from "node:process";

// --- Enkel CSV-parser (semikolon-separert) ---
function lesCSV(filsti) {
  const linjer = readFileSync(filsti, "utf-8").trim().split(/\r?\n/);
  const [headerLinje, ...rest] = linjer;
  const headers = headerLinje.split(";");
  return rest.map(linje => {
    const verdier = linje.split(";");
    return Object.fromEntries(headers.map((h, i) => [h, verdier[i]]));
  });
}

function aktivitetsnavn(data) {
  return Object.keys(data[0]).filter(k => k !== "Fylke");
}

function totalerPerAktivitet(data) {
  const aktiviteter = aktivitetsnavn(data);
  const result = {};
  for (const a of aktiviteter) {
    result[a] = data.reduce((s, rad) => s + Number(rad[a]), 0);
  }
  return result;
}

function visTotaltabell(totaler) {
  console.log(`\n${"Aktivitet".padEnd(28)}${"Total".padStart(10)}`);
  console.log("-".repeat(38));
  Object.entries(totaler)
    .sort(([, a], [, b]) => b - a)
    .forEach(([navn, total]) => {
      console.log(navn.padEnd(28) + String(total).padStart(10));
    });
}

function visFylke(data, fylke) {
  const rad = data.find(r => r.Fylke.toLowerCase() === fylke.toLowerCase());
  if (!rad) {
    console.log(`Fylket '${fylke}' ble ikke funnet.`);
    return null;
  }
  const aktiviteter = aktivitetsnavn(data);
  const par = aktiviteter
    .map(a => [a, Number(rad[a])])
    .sort(([, a], [, b]) => a - b);
  const total = par.reduce((s, [, v]) => s + v, 0) || 1;

  console.log(`\nAktiviteter i ${rad.Fylke} (sortert stigende):`);
  console.log(`${"Aktivitet".padEnd(28)}${"Antall".padStart(8)}${"Prosent".padStart(10)}`);
  par.forEach(([a, v]) => {
    const p = ((v / total) * 100).toFixed(1);
    console.log(a.padEnd(28) + String(v).padStart(8) + `${p} %`.padStart(10));
  });
  return rad;
}

// 8c — Topp 3 som SVG-stolpediagram (uten eksterne bibliotek)
import { writeFileSync } from "node:fs";
function toppTreSvg(data, fylke) {
  const rad = data.find(r => r.Fylke.toLowerCase() === fylke.toLowerCase());
  if (!rad) return;
  const aktiviteter = aktivitetsnavn(data);
  const topp3 = aktiviteter
    .map(a => [a, Number(rad[a])])
    .sort(([, a], [, b]) => b - a)
    .slice(0, 3);

  const bredde = 600, hoyde = 400, padding = 60;
  const maks = Math.max(...topp3.map(t => t[1]));
  const stolpebredde = (bredde - padding * 2) / topp3.length - 10;
  const farger = ["#2196F3", "#4CAF50", "#FFC107"];

  let svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${bredde}" height="${hoyde}">`;
  svg += `<text x="${bredde/2}" y="30" text-anchor="middle" font-size="18" font-weight="bold">Topp 3 friluftsaktiviteter i ${rad.Fylke}</text>`;
  topp3.forEach(([navn, v], i) => {
    const h = ((hoyde - padding * 2) * v) / maks;
    const x = padding + i * (stolpebredde + 20);
    const y = hoyde - padding - h;
    svg += `<rect x="${x}" y="${y}" width="${stolpebredde}" height="${h}" fill="${farger[i]}"/>`;
    svg += `<text x="${x + stolpebredde/2}" y="${hoyde - padding + 20}" text-anchor="middle">${navn}</text>`;
    svg += `<text x="${x + stolpebredde/2}" y="${y - 6}" text-anchor="middle" font-weight="bold">${v}</text>`;
  });
  svg += `</svg>`;
  writeFileSync(`topp3_${rad.Fylke.replace(/ /g, "_")}.svg`, svg);
  console.log(`\nDiagram lagret som topp3_${rad.Fylke.replace(/ /g, "_")}.svg`);
}

async function main() {
  const data = lesCSV("friluftsaktiviteter_2024.csv");
  visTotaltabell(totalerPerAktivitet(data));

  const rl = readline.createInterface({ input, output });
  const fylke = (await rl.question("\nVelg et fylke (f.eks. Oslo): ")).trim();
  rl.close();

  visFylke(data, fylke);
  toppTreSvg(data, fylke);
}

main();

Oppgave 9 – Skogbrann-simulering (HTML5 Canvas)

// skogbrann.html — kjøres direkte i nettleseren
// Lagre koden under som skogbrann.html og åpne i nettleser.

<!DOCTYPE html>
<html lang="no">
<head><meta charset="utf-8"><title>Skogbrann</title></head>
<body style="background:#222;color:#eee;font-family:sans-serif;text-align:center">
<h2>Skogbrann-simulering</h2>
<canvas id="lerret" width="560" height="560"></canvas>
<script>
const RUTER = 40;
const CELLE = 14;
const P_VOKS = 0.003;     // sannsynlighet for at tom celle blir tre
const P_LYN = 0.0003;     // sannsynlighet for lynnedslag på tre

const TILSTAND = { TOM: 0, TRE: 1, BRANN: 2 };
const FARGER = ["#e8d7b9", "#2e7d32", "#e53935"];

class Skog {
  constructor(rader, kolonner) {
    this.rader = rader;
    this.kolonner = kolonner;
    this.celler = Array.from({length: rader},
      () => Array.from({length: kolonner}, () => TILSTAND.TOM));
  }
  brennerNoe() {
    return this.celler.flat().includes(TILSTAND.BRANN);
  }
  naboer(r, k) {
    const result = [];
    for (const [dr, dk] of [[-1, 0], [1, 0], [0, -1], [0, 1]]) {
      const nr = r + dr, nk = k + dk;
      if (nr >= 0 && nr < this.rader && nk >= 0 && nk < this.kolonner) {
        result.push([nr, nk]);
      }
    }
    return result;
  }
  tick() {
    const ny = this.celler.map(rad => [...rad]);
    const brenner = this.brennerNoe();
    for (let r = 0; r < this.rader; r++) {
      for (let k = 0; k < this.kolonner; k++) {
        const t = this.celler[r][k];
        if (t === TILSTAND.BRANN) {
          ny[r][k] = TILSTAND.TOM;
          for (const [nr, nk] of this.naboer(r, k)) {
            if (this.celler[nr][nk] === TILSTAND.TRE) ny[nr][nk] = TILSTAND.BRANN;
          }
        } else if (t === TILSTAND.TRE) {
          if (Math.random() < P_LYN) ny[r][k] = TILSTAND.BRANN;
        } else if (t === TILSTAND.TOM && !brenner) {
          if (Math.random() < P_VOKS) ny[r][k] = TILSTAND.TRE;
        }
      }
    }
    this.celler = ny;
  }
}

const ctx = document.getElementById("lerret").getContext("2d");
const skog = new Skog(RUTER, RUTER);

function tegn() {
  for (let r = 0; r < skog.rader; r++) {
    for (let k = 0; k < skog.kolonner; k++) {
      ctx.fillStyle = FARGER[skog.celler[r][k]];
      ctx.fillRect(k * CELLE, r * CELLE, CELLE, CELLE);
    }
  }
}

function loop() {
  skog.tick();
  tegn();
  setTimeout(loop, skog.brennerNoe() ? 40 : 100);
}

tegn();
setTimeout(loop, 100);
</script>
</body></html>
Designvalg for sensor:
  • Klassefordeling: Skog-klassen håndterer modell og logikk; tegning skjer i ren funksjon mot Canvas-konteksten — ren separasjon av modell og view.
  • Synkron oppdatering: Vi beregner ny-rutenettet før vi skriver tilbake, slik at brannen ikke «løper» tvers over kartet på ett trinn.
  • Tidsskala: Trær vokser bare når det ikke brenner (kravet), og brann-ticken er raskere enn vekst-ticken (40 vs. 100 ms).

Oppgave 10 – Innlevering

123456/
├── oppgave5b/oppgave5b.mjs
├── oppgave6/
│   ├── bibliotek.mjs
│   └── test_bibliotek.mjs
├── oppgave8/
│   ├── oppgave8.mjs
│   ├── friluftsaktiviteter_2024.csv
│   └── topp3_Oslo.svg
├── oppgave9/skogbrann.html
└── README.md   (krev: Node.js 18+ for ESM/Top-level await)
Laster…
Eldre løsning
Høst 2024

Alle løsningsforslag for IT 2 – JavaScript

Vår 2025Høst 2024Vår 2024Høst 2023
Se eksamensoppgaven
eksamenssett.noTren målrettet

Komplett samling av eksamensoppgaver og løsninger for norsk skole.

Om ossFAQPersonvernVilkårAngrerettKontakt

© 2025 Eksamenssett.no · Alle rettigheter forbeholdt

Innholdet er utviklet med AI-verktøy og kvalitetssikres kontinuerlig. Slik jobber vi med kvalitet →

Eksamenssett.no eies og drives av Studenthjelp Privatundervisning AS