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 Høst 2023
VG3

Løsningsforslag Informasjonsteknologi IT 2 – JavaScriptHøst 2023

Se eksamensoppgaven
Vår 2024Nyere
Om løsningsforslaget: Dette er et veiledende løsningsforslag laget av eksamenssett.no for REA3049-JS Høst 2023. Vi gir korrekte svar på flervalgsoppgavene med begrunnelse, fullstendig JavaScript-kode for programmeringsoppgavene (5, 7c, 11, 12), og eksempelsvar på drøftingsoppgavene om finanssektoren og personvern (10).

Løsningsforslag – IT 2 JavaScript Høst 2023

Eksamen: REA3049-JS | Semester: Høst 2023 | Tema: Pseudokode-grunnlag, OOP-prinsipper, billettsystem-flytdiagram, nest-størst-algoritme, IoT-personvern, YouTube-datasett, Manic Mansion-spill

Oppgave 1 – Hva kjennetegner IKKE pseudokode?

Riktig svar: Den kan kjøres direkte på en datamaskin.

Pseudokode er ikke kjørbar — den ligner på menneskespråk, har uformell syntaks og brukes i planleggingsfasen.

Oppgave 2 – For- og while-løkker

Riktig svar: en for-løkke er best egnet når du vet hvor mange ganger du vil at løkken skal kjøre

For-løkker passer for kjente, faste antall iterasjoner. While-løkker passer når avslutningsbetingelsen er dynamisk eller ukjent på forhånd.

Oppgave 3 – Hovedprinsippet bak OOP

Riktig svar: å representere data og funksjoner som objekter

OOP samler data (felter) og oppførsel (metoder) i objekter, slik at programmet modellerer virkeligheten i form av selvstendige enheter som kan kommunisere.

Oppgave 4 – Pseudokode som skriver ut 1–5

Riktige svar: Alternativ 1 og Alternativ 3
Alt.Kort beskrivelseSkriver ut
1FOR i ≤ 5: PRINT i1, 2, 3, 4, 5 ✅
2WHILE i < 5: PRINT i; INCREMENT1, 2, 3, 4 (mangler 5) ❌
3FOR i ≤ 4: PRINT i+11, 2, 3, 4, 5 ✅
4WHILE i ≤ 5: PRINT i; INCREMENT BY 21, 3, 5 (kun oddetall) ❌

Oppgave 5 – Flytdiagram for billettpris

Oppgaven: Lag flytdiagram: barn (≤15) 30 kr, voksen (16–66) 50 kr, pensjonist (≥67) 35 kr.
  ┌──────────┐
  │  START   │
  └────┬─────┘
       ▼
  LES alder
       ▼
   ╱ alder ≤ 15? ╲────Ja──▶ DISPLAY "Barnebillett: 30 kr"
        Nei
       ▼
   ╱ alder ≥ 67? ╲────Ja──▶ DISPLAY "Pensjonistbillett: 35 kr"
        Nei
       ▼
  DISPLAY "Voksenbillett: 50 kr"
       ▼
  ┌──────────┐
  │  SLUTT   │
  └──────────┘

Tilsvarende JavaScript-implementasjon (også nyttig som referanse):

function billettpris(alder) {
  if (alder <= 15) return "Barnebillett: 30 kr";
  if (alder >= 67) return "Pensjonistbillett: 35 kr";
  return "Voksenbillett: 50 kr";
}

Oppgave 6 – Nest-største tall

Oppgave 6a – Hvilke to løsninger er riktige?

Riktige svar: Alternativ 2 og Alternativ 4
Alt.StrategiKorrekt?Hvorfor
1Finn størst, fjern den, finn nest-størst❌«Fjern størst» fjerner bare én av flere like maks-verdier.
2Initialiser med to første verdier, oppdater nøye✅Sjekken tall ≠ størst sikrer at duplikater ikke regnes som nest-størst.
3Én løkke uten likhets-sjekk❌Mangler sjekk på likhet — i [9, 9, 5] returnerer den 9 som nest-størst.
4Sorter, finn første som er ulik forrige✅Korrekt selv ved duplikater.

Oppgave 6b – Sammenligning av løsning 2 og 4

Tidskompleksitet: Løsning 2 er O(n) — én pass. Løsning 4 er O(n log n) på grunn av sortering. For store lister er løsning 2 betydelig raskere.

Plasskompleksitet: Løsning 2 bruker konstant ekstra plass. Løsning 4 trenger plass til den sorterte listen, eller endrer originalen.

Lesbarhet: Løsning 4 er enklere og kortere — sortering er en velkjent operasjon. Løsning 2 har mer betingelseslogikk.

Konklusjon: Løsning 4 vinner på lesbarhet, løsning 2 på effektivitet. For typiske skoleeksempler er løsning 4 mest attraktiv; for store datasett bør man velge løsning 2.

Oppgave 7c – Implementasjon av nest-størst-algoritme

// nest_storst.mjs — to korrekte løsninger

export function nestStorstLineaer(tall) {
  if (tall.length < 2) return null;
  let storst = -Infinity, nestStorst = -Infinity;
  for (const t of tall) {
    if (t > storst) {
      nestStorst = storst;
      storst = t;
    } else if (t < storst && t > nestStorst) {
      nestStorst = t;
    }
  }
  return nestStorst === -Infinity ? null : nestStorst;
}

export function nestStorstSortert(tall) {
  if (tall.length < 2) return null;
  const sortert = [...tall].sort((a, b) => b - a);
  const storst = sortert[0];
  for (const t of sortert.slice(1)) {
    if (t !== storst) return t;
  }
  return null;
}

// Tester
const eksempler = [
  [9, 9, 5, 3],     // forventet: 5
  [1, 2, 3, 4, 5],   // forventet: 4
  [7],              // forventet: null
  [3, 3, 3],        // forventet: null
];
eksempler.forEach(e =>
  console.log(`${JSON.stringify(e).padEnd(18)} → lineær=${nestStorstLineaer(e)}, sortert=${nestStorstSortert(e)}`)
);

Oppgave 9 – IoT-risikovurdering

Riktig svar: for å forsikre seg om at produktene er trygge og overholder personvernregelverket

IoT-enheter samler ofte sensitive opplysninger. GDPR-brudd kan føre til store bøter (opptil 4 % av global omsetning) og omdømmetap.

Oppgave 10 – Endring i finanssektoren + personverndilemma

Oppgave 10a – Endring forårsaket av IT

Endring: Den mest gjennomgripende endringen i finanssektoren er overgangen til digitale betalingsløsninger — Vipps, BankID, mobilbank — som har erstattet kontant og papirgiro. Norge er blant verdens mest «kontantløse» økonomier; under 3 % av betalinger skjer med kontanter (Norges Bank, 2023).

Endringen er drevet av smarttelefonens utbredelse, sikker autentisering med BankID, åpne API-er gjennom PSD2-direktivet, og maskinlæringsbasert svindeldeteksjon. Tradisjonelle banker har gått fra fysiske filialer til app-styrt selvbetjening, og fintech-aktører (Klarna, Revolut, Wise) konkurrerer direkte med etablerte banker.

Oppgave 10b – Personverndilemma

Dilemmaet: Når alle transaksjoner er digitale, etterlater hvert kjøp en datasti — hva, hvor, når og hvor mye. Bankene kan slutte seg til helsetilstand (apotek), politisk engasjement (donasjoner), forhold (hotellopphold) og hele livsstilen.

Spenning: Dataene er nyttige for svindelhindring og rådgivning, men også svært sensitive. Lekkasje eller misbruk kan brukes til diskriminering (kredittavslag basert på «livsstil»), målrettet manipulasjon, eller statlig overvåkning.

GDPR og dataminimering: Forordningen krever at banker bare lagrer det de trenger til avtalt formål — men «svindeldeteksjon» og «kunderelasjon» er bredt nok til at lite begrenses i praksis. PSD2 gir kunden rett til å overføre data til andre tilbydere, men gjør samtidig at flere aktører får tilgang.

Vurdering: Den kontantløse økonomiens bekvemmelighet kommer med en pris i form av redusert anonymitet. Et velregulert system kan dempe risikoen, men aldri fjerne den.

Oppgave 11 – YouTube-statistikk

// oppgave11.mjs — analyse av YouTube-datasett
/* Forberedelse: datasettet kan være kodet med ukjent tegnsett (UTF-8 eller latin-1).
 * Numeriske kolonner er kodet som tekst — vi konverterer der det kreves.
 * Tomme/nan land-felter ignoreres. */

import { readFileSync } from "node:fs";

function lesData(filsti = "youtube.csv") {
  let tekst;
  try { tekst = readFileSync(filsti, "utf-8"); }
  catch { tekst = readFileSync(filsti, "latin1"); }

  const linjer = tekst.trim().split(/\r?\n/);
  const [head, ...rest] = linjer;
  const headers = head.split(",");
  return rest.map(linje => {
    const v = linje.split(",");
    return Object.fromEntries(headers.map((h, i) => [h.trim(), (v[i] || "").trim()]));
  });
}

function tilTall(s) {
  const n = parseFloat((s || "").replace(/,/g, ""));
  return Number.isFinite(n) ? n : 0;
}

function toppTiLand(data) {
  const teller = new Map();
  for (const r of data) {
    const land = (r.Country || r.country || "").trim();
    if (land && land.toLowerCase() !== "nan") {
      teller.set(land, (teller.get(land) || 0) + 1);
    }
  }
  return [...teller.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10);
}

function snittPerLand(data, land) {
  const samletAbo = new Map(), samletViews = new Map(), antall = new Map();
  const landset = new Set(land);
  for (const r of data) {
    const l = (r.Country || r.country || "").trim();
    if (landset.has(l)) {
      samletAbo.set(l, (samletAbo.get(l) || 0) + tilTall(r.subscribers));
      samletViews.set(l, (samletViews.get(l) || 0) + tilTall(r["video views"]));
      antall.set(l, (antall.get(l) || 0) + 1);
    }
  }
  const result = {};
  for (const l of land) {
    const n = antall.get(l) || 1;
    result[l] = { abo: samletAbo.get(l) / n, views: samletViews.get(l) / n };
  }
  return result;
}

function main() {
  const data = lesData();
  const topp = toppTiLand(data);
  console.log("\nTopp 10 land etter antall YouTube-kanaler:");
  topp.forEach(([land, n], i) => console.log(`${(i+1).toString().padEnd(4)}${land.padEnd(20)}${n}`));

  const snitt = snittPerLand(data, topp.map(([l]) => l));
  console.log("\nGjennomsnitt per kanal i topp 10:");
  topp.forEach(([land]) => {
    const {abo, views} = snitt[land];
    console.log(`${land.padEnd(20)}${abo.toLocaleString("nb-NO", {maximumFractionDigits:0}).padStart(15)} abonnenter${views.toLocaleString("nb-NO", {maximumFractionDigits:0}).padStart(20)} visninger`);
  });
}

main();

Oppgave 12 – Manic Mansion (Canvas-spill)

Oppgave 12a – Forklaring av modellen

En naturlig OO-modell består av en abstrakt Spillobjekt-klasse med posisjon og størrelse, og fire spesialiseringer: Menneske (styres av piltaster), Spokelse (beveger seg konstant, reflekteres ved kanter), Hindring (statisk, blokkerer Menneske), og Sau (statisk inntil bæres). I tillegg har vi en Spill-klasse som holder rede på alle objekter, oppdager kollisjoner, og kjører hovedløkken.

Oppgave 12b – Implementasjon (HTML5 Canvas)

<!DOCTYPE html>
<html lang="no">
<head><meta charset="utf-8"><title>Manic Mansion</title></head>
<body style="text-align:center;font-family:sans-serif;background:#222;color:#eee">
<h2>Manic Mansion</h2>
<canvas id="lerret" width="800" height="600" tabindex="0" style="background:#e8d7b9;outline:none"></canvas>
<p id="info">Bruk piltaster eller WASD for å bevege deg.</p>
<script>
const BREDDE = 800, HOEYDE = 600, FRISONE = 80, FPS = 60;
const MENNESKE_FART = 4, SAU_BREMS = 0.5, SPOKELSE_FART = 3;

class Spillobjekt {
  constructor(x, y, storrelse, farge) {
    this.x = x; this.y = y; this.storrelse = storrelse; this.farge = farge;
  }
  rect() {
    const s = this.storrelse;
    return { x: this.x - s/2, y: this.y - s/2, w: s, h: s };
  }
  tegn(ctx) {
    ctx.fillStyle = this.farge;
    const r = this.rect();
    ctx.fillRect(r.x, r.y, r.w, r.h);
  }
}

function kolliderer(a, b) {
  const ar = a.rect(), br = b.rect();
  return ar.x < br.x + br.w && ar.x + ar.w > br.x && ar.y < br.y + br.h && ar.y + ar.h > br.y;
}

class Menneske extends Spillobjekt {
  constructor(x, y) {
    super(x, y, 28, "#1a2b4a");
    this.bærerSau = false;
    this.poeng = 0;
  }
  fart() { return MENNESKE_FART * (this.bærerSau ? SAU_BREMS : 1); }
  oppdater(taster, hindringer) {
    const f = this.fart();
    let nx = this.x, ny = this.y;
    if (taster.has("ArrowLeft") || taster.has("a")) nx -= f;
    if (taster.has("ArrowRight") || taster.has("d")) nx += f;
    if (taster.has("ArrowUp") || taster.has("w")) ny -= f;
    if (taster.has("ArrowDown") || taster.has("s")) ny += f;

    const s = this.storrelse / 2;
    nx = Math.max(s, Math.min(BREDDE - s, nx));
    ny = Math.max(s, Math.min(HOEYDE - s, ny));

    // Aksevis kollisjonshåndtering
    const forrigeX = this.x, forrigeY = this.y;
    this.x = nx;
    if (hindringer.some(h => kolliderer(this, h))) this.x = forrigeX;
    this.y = ny;
    if (hindringer.some(h => kolliderer(this, h))) this.y = forrigeY;
  }
}

class Spokelse extends Spillobjekt {
  constructor(x, y) {
    super(x, y, 24, "#e57373");
    const v = Math.random() * 2 * Math.PI;
    this.dx = Math.cos(v) * SPOKELSE_FART;
    this.dy = Math.sin(v) * SPOKELSE_FART;
  }
  oppdater() {
    this.x += this.dx; this.y += this.dy;
    const s = this.storrelse / 2;
    if (this.x < s || this.x > BREDDE - s) this.dx = -this.dx;
    if (this.y < s || this.y > HOEYDE - s) this.dy = -this.dy;
    // Hold spøkelser ute av frisonene
    if (this.x < FRISONE + s) this.dx = Math.abs(this.dx);
    if (this.x > BREDDE - FRISONE - s) this.dx = -Math.abs(this.dx);
  }
}
class Hindring extends Spillobjekt { constructor(x, y) { super(x, y, 36, "#785038"); } }
class Sau extends Spillobjekt { constructor(x, y) { super(x, y, 22, "#f0f0e6"); } }

class Spill {
  constructor() {
    this.menneske = new Menneske(40, HOEYDE / 2);
    this.spokelser = []; this.hindringer = []; this.sauer = [];
    this.tapt = false;
    this._nySpokelse(); this._nyHindring(); this._nyHindring(); this._nyHindring();
    this._nySau(); this._nySau(); this._nySau();
  }
  _tilfeldigMidten() {
    return [
      FRISONE + 30 + Math.random() * (BREDDE - 2 * FRISONE - 60),
      30 + Math.random() * (HOEYDE - 60)
    ];
  }
  _nySpokelse() { const [x, y] = this._tilfeldigMidten(); this.spokelser.push(new Spokelse(x, y)); }
  _nyHindring() { const [x, y] = this._tilfeldigMidten(); this.hindringer.push(new Hindring(x, y)); }
  _nySau() {
    const x = BREDDE - FRISONE + 10 + Math.random() * (FRISONE - 30);
    const y = 20 + Math.random() * (HOEYDE - 40);
    this.sauer.push(new Sau(x, y));
  }
  oppdater(taster) {
    if (this.tapt) return;
    this.menneske.oppdater(taster, this.hindringer);
    this.spokelser.forEach(s => s.oppdater());

    if (this.spokelser.some(s => kolliderer(this.menneske, s))) { this.tapt = true; return; }

    if (!this.menneske.bærerSau) {
      const idx = this.sauer.findIndex(s => kolliderer(this.menneske, s));
      if (idx !== -1) {
        this.sauer.splice(idx, 1);
        this.menneske.bærerSau = true;
      }
    } else {
      if (this.menneske.x < FRISONE) {
        this.menneske.bærerSau = false;
        this.menneske.poeng++;
        this._nySau(); this._nySpokelse(); this._nyHindring();
      } else if (this.sauer.some(s => kolliderer(this.menneske, s))) {
        this.tapt = true;
      }
    }
  }
  tegn(ctx) {
    ctx.fillStyle = "#e8d7b9"; ctx.fillRect(0, 0, BREDDE, HOEYDE);
    ctx.fillStyle = "#c8e0c8";
    ctx.fillRect(0, 0, FRISONE, HOEYDE);
    ctx.fillRect(BREDDE - FRISONE, 0, FRISONE, HOEYDE);
    [...this.hindringer, ...this.sauer, ...this.spokelser, this.menneske].forEach(o => o.tegn(ctx));
    ctx.fillStyle = "#000"; ctx.font = "20px sans-serif";
    ctx.fillText(`Poeng: ${this.menneske.poeng}${this.tapt ? "  — TAPT" : ""}`, 10, 25);
  }
}

const spill = new Spill();
const ctx = document.getElementById("lerret").getContext("2d");
const taster = new Set();
window.addEventListener("keydown", e => taster.add(e.key));
window.addEventListener("keyup", e => taster.delete(e.key));
document.getElementById("lerret").focus();

function loop() {
  spill.oppdater(taster);
  spill.tegn(ctx);
  requestAnimationFrame(loop);
}
loop();
</script></body></html>
Designvalg for sensor:
  • Polymorfisme via arv: Alle objekter arver fra Spillobjekt og overstyrer oppdater()/tegn() ved behov.
  • Aksevis kollisjonshåndtering for menneske gir naturlig «glide langs vegg»-følelse.
  • Frisoner er enkle x-grenser; spøkelser reflekteres når de prøver å gå inn, mennesket har lov.
  • Tap-tilstand stopper bare bevegelsen — vinduet kan fortsatt brukes.

Oppgave 13 – Innlevering

123456/
├── oppgave5/billettpris_flytdiagram.pdf
├── oppgave7c/nest_storst.mjs
├── oppgave11/
│   ├── oppgave11.mjs
│   └── youtube.csv
├── oppgave12/manic_mansion.html
└── README.md
Nyere løsning
Vår 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