Översikt
Fjärde kursveckan! Veckan inleds med en repetition och ett större exempel för att sedan titta på veckans huvudtema, Arrayer! Information om veckans upplägg annonseras löpande i kursens Zulip-kanal.
Veckostart med arrayer och A2
Section titled “Veckostart med arrayer och A2”Tisdagen i kursvecka 4 gick Mats och Mikael igenom veckans material. Mikael livekodade grunderna i
arrayer, och Mats visade hur du kommer igång med examinationsuppgift A2, från att skapa repot och
tämja en kraschande app.js till att köra utvalda tester och göra din första commit. Passet
avslutades med frågor om bedömning, commits och AI-användning i A2.
Om passet
Section titled “Om passet”Tisdagens pass i kursvecka 4 hölls av Mats och Mikael tillsammans och bestod av tre delar: en kort genomgång av veckans material, en oförberedd livekodning kring arrayer i Mikaels playground-projekt, och en demonstration av hur man kommer igång med examinationsuppgift A2 — från att skapa sitt repo till första commit. Passet avslutades med frågor om A2, bedömning och AI-användning.
Veckans material
Section titled “Veckans material”Veckans huvudtema är arrayer, och kunskapen är en direkt förutsättning för A2 — tillsammans med undantag (exceptions) och allt från kursvecka 1–3. Den första stödjande inspelningen (exemplet Vilket Unicode-värde) handlar inte om arrayer alls utan är en repetition av funktioner och moduler. Därefter följer den långa inspelningen om arrayer (ca en och en halv timme), vars presentation reviderats för 2026 — själva grundkonceptet har inte förändrats sedan Mats lärde sig det på 80-talet, men det har tillkommit nya hjälpmetoder. Läsanvisningarna omfattar ungefär 28 sidor, och MDN och Eloquent JavaScript täcker samma stoff. Veckan har sex utmaningar.
Övningsuppgifterna är märkta med olika svårighetsgrad eftersom spännvidden bland kursens studenter är stor. Är du helt nybörjare räcker det gott med Grunderna med arrayer, Additionell kopia av array och Sorterad kopia av array — kan du det de tar upp står du väl rustad inför A2.
Livekodning: en array och en for-loop
Section titled “Livekodning: en array och en for-loop”Mikael visar hur han själv lär sig (eller fräschar upp) ett språk: han skriver små, små program i ett separat playground-projekt och provkör efter varje steg. Han liknar en array vid en byrå med numrerade lådor — varje låda har en position och innehåller ett värde:
const data = ['hej', 'på', 'dig', 'trevlig', 'dag']
for (let i = 0; i < data.length; i++) { console.log(`${i}: ${data[i]}`)}Index börjar på 0, så det sista elementet ligger på data.length - 1. Mats lyfter fram det som
ofta är förvirrande i början: hakparenteserna betyder olika saker beroende på var de står. Till höger
om tilldelningen skapar de en array (en array-litteral; [] är en tom array), efter ett
variabelnamn används de för att komma åt ett element via dess index. JavaScript har, som många
C-liknande språk, nollbaserade index. I Pascal, som Mats lärde sig på, väljer man själv indexgränserna
och det vanliga är att börja på 1.
Mallsträngar och den döda backtick-tangenten
Section titled “Mallsträngar och den döda backtick-tangenten”En inskickad fråga gällde konstruktionen ${...} i utskriften. Strängen omges av backticks, vilket
gör den till en mallsträng (template literal), även kallad interpolerande sträng: uttryck inom
${} beräknas och deras värden infogas i strängen. Med vanliga citattecken skrivs texten i stället
ut precis som den står. Mikael visar också att samma utskrift går att få med vanlig konkatenering,
i + ': ' + data[i] — två vägar till samma resultat.
På ett svenskt tangentbord är backtick en död tangent: Shift + tangenten till vänster om Backspace ger inget tecken förrän man trycker en tangent till (t.ex. Blanksteg) — annars kombineras den med nästa bokstav till ett diakritiskt tecken. Lätt att fastna på om man inte känner till det.
Index utanför arrayen, mittersta elementet och at()
Section titled “Index utanför arrayen, mittersta elementet och at()”data[5]på en array med fem element går inte sönder — JavaScript returnerar baraundefined. Mats och Mikael är överens om att det kan diskuteras om det är snällt eller inte.- En students fråga om man kan dela
data.lengthmed två för att hitta mittersta elementet testas live. Med fem element blir5 / 2lika med2.5, ochdata[2.5]gerundefined— ett index måste vara ett heltal. Mikael avrundar därför medMath.round(),Math.floor()ochMath.ceil().Math.round(2.5)blir3(Math.round()avrundar ett.5-värde uppåt mot positiv oändlighet),Math.floor(2.5)blir2ochMath.ceil(2.5)blir3. Observera att det mittersta elementet i en array med fem element ligger på index2— för udda längder är det alltsåMath.floor(data.length / 2)som ger rätt index. Mikael påpekar att just detta, att hitta mitten och hantera fallet med två mittersta element, är en del av A2 (medianen). - Att komma åt sista eller näst sista elementet med
data[data.length - 1]ochdata[data.length - 2]fungerar men är klumpigt. Mats visar attdata.at(-1)ger sista elementet ochdata.at(-2)det näst sista. Metoden tillkom i en senare version av språket. JavaScript (ECMAScript) får en ny version varje år, och önskemål från utvecklarna letar sig så småningom in i språket.
Poängen Mikael gör är att konstruktionerna går igen i alla språk, även om syntaxen skiljer sig, och att playground-projektet med tiden blir en egen liten uppslagsbok. Det är också ett säkrare ställe att experimentera på än mitt i examinationsuppgiften, där man riskerar att förstöra kod man redan skrivit.
Kom igång med A2: repot
Section titled “Kom igång med A2: repot”Mats utgår från att han inte gjort det som rekommenderades i kursvecka 3 och skapar sitt A2-repo från början:
- I ActionHub väljer han examinationsuppgift A2 bland distansresurserna och klickar på Create my GitLab resources. Det kan ta en stund innan repot dyker upp i ens egen grupp på GitLab.
- Repot har bara en enda commit, skapad utifrån mallen. Det är nytt för i år och underlättar för kursledningen vid bedömningen.
- Repot hanteras från och med nu precis som en övningsuppgift: han klonar det via SSH till sin
katalog för examinationsuppgifter, går in i katalogen med
cdoch öppnar VS Code medcode .. npm installinstallerar beroendena.
Om ActionHub redan visar alla examinationsuppgifter som skapade går det inte att ångra som student, det kräver kursledningen. Skriv i så fall på Zulip.
app.js kraschar — och det är meningen
Section titled “app.js kraschar — och det är meningen”Koden finns i src/: app.js och statistics.js. app.js examineras inte. Det är
statistics.js som ska implementeras. Kör man npm start direkt efter kloningen kraschar
programmet, eftersom app.js importerar funktioner (t.ex. average) som statistics.js ännu
inte exporterar. Det är helt i sin ordning.
Rådet är att inte vara rädd för att kommentera bort stora delar av app.js medan man arbetar, och
bygga upp ett eget litet huvudprogram steg för steg: importera average, skapa en minimal
exporterad funktion i statistics.js som bara loggar något, anropa den från app.js och
provköra. Hur app.js ser ut vid inlämningen spelar enligt Mats ingen roll — bedömningen utgår
från att testerna går igenom.
Köra en delmängd av testerna
Section titled “Köra en delmängd av testerna”Uppgiften har ca 170 tester, och det är inte särskilt uppmuntrande att se alla misslyckas hela
tiden. npm run test:run kör samtliga. Med VS Code-tillägget för Vitest (samma som strulade i
förra veckans pass, som behövde avinstalleras och installeras om) kan man i vyn Testing peka ut
och köra bara testerna för en funktion, t.ex. average: 23 tester körs och övriga hoppas över.
Mats beskriver det som ett mycket bättre hjälpmedel för en så här stor uppgift än att köra
testerna i terminalen.
Kraven: README, issues och work items
Section titled “Kraven: README, issues och work items”Uppgiftsbeskrivningen finns i repots README, men alla krav står inte där. Från README länkas till
issues (som GitLab sedan några veckor samlar under paraplybegreppet work items) med ytterligare
krav. Issuen för average anger bland annat att funktionen ska exporteras, beräkna och returnera
medelvärdet, validera indata, sakna sidoeffekter och inte själv fånga några undantag. Felhanteringen
sköts av app.js.
Kraven har kryssrutor som du kan bocka av allteftersom, du kan skriva kommentarer i issuen, och när en funktion är helt klar kan du stänga issuen. Listan Work items (17 öppna från början) ger en överblick över samtliga krav, medan README visar dem i sitt sammanhang. Att arbeta mot issues är vanligt i riktiga programmeringsprojekt.
Pipelinen, lint och commits
Section titled “Pipelinen, lint och commits”Ett rött kryss vid senaste commit på GitLab betyder att pipelinen inte gått igenom. Klickar man på
krysset ser man vilka steg som fallerat: kodkvaliteten (lint) och testerna. Testerna blir inte gröna
förrän uppgiften är klar, men lint-steget kan bli grönt tidigare eftersom det bara granskar den kod
som finns. Samma kontroller kan köras lokalt: npm run lint visar exakt vad som är fel och
npm run lint:fix rättar det som går att rätta automatiskt.
Du behöver inte vänta tills en funktion är färdig innan du committar — en tom men exporterad
funktion räcker. Mats glömmer i förbigående att köra git add före git commit, ett vanligt
misstag. En student tipsar om git commit -a -m "...", som tar med ändringar i redan
versionshanterade filer utan separat git add (nya filer måste fortfarande läggas till). Glöm inte
heller git push — en lokal commit syns inte på GitLab.
Uppgiften kräver minst 15 commits. Mats skulle själv landa runt 20. Commit-meddelanden får skrivas
på engelska eller svenska, huvudsaken är att man är konsekvent. De skrivs i imperativ form
(Add average, inte Added average), gärna utan artiklar. Kod, kommentarer och variabelnamn
skriver man lämpligen på engelska.
AI i A2
Section titled “AI i A2”En inskickad fråga gällde om man måste använda AI för att lösa A2. Svaret är nej: ingen examinationsuppgift förutsätter AI-användning. Reflektionsdokumentet har en del om hur du arbetat med AI, och har du inte använt AI skriver du det där. Använder du AI redovisar du hur. Det är ditt eget val och ditt eget ansvar. Poängen är att lära sig, inte bara att lösa uppgiften, och oavsett arbetssätt ska du förstå det du lämnar in. Mer om detta finns under Akademisk integritet i kursens studieguide.
Mikaels egen rekommendation är att kämpa på egen hand och faktiskt undvika AI i just denna uppgift. Den är inte särskilt svår, mest skolmatematik, även om några delar är knepigare. Han beskriver två ytterligheter han möter vid bedömning. Slarvig men fungerande kod är i det här skedet ett gott tecken på att någon verkligen försökt själv. Extremt kompakt, kedjad funktionell kod väcker frågan om studenten verkligen lärt sig något, och den är svår att ge meningsfull återkoppling på.
Bedömning och inlämning
Section titled “Bedömning och inlämning”- Grön pipeline är ett krav men ingen garanti. Är testerna eller kodanalysen röda deltar inlämningen inte ens i bedömningen och blir automatiskt underkänd. Är allt grönt bedömer en examinator (Mats eller Mikael) uppgiften manuellt, eftersom allt inte kan kontrolleras med tester.
- Inlämningen görs via en merge request. Kursledningen bedömer den, stänger den och sätter etiketter för godkänt eller inte, så hela flödet med bedömning och återkoppling sker på GitLab.
- A2 har ingen muntlig examination. Det har nästa uppgift, A3.
- För få commits är inget stort problem, det går att rätta genom att fortsätta med fler, mindre commits. Inkonsekvent språk i commit-meddelanden ger på sin höjd en kommentar.
Kommentarer i koden
Section titled “Kommentarer i koden”Det enda kravet är det som kursens kodstandard ställer: JSDoc-kommentarer som beskriver vad en funktion gör, dess parametrar, returvärde och eventuella undantag som kastas. I övrigt är pedagogiska kommentarer som hjälper dig själv att förstå koden, gärna på varje rad, helt okej efter tre–fyra veckor i kursen, även om det inte är så kod ser ut efter tre års studier.
Förbered dig redan nu för A3:s muntliga examination
Section titled “Förbered dig redan nu för A3:s muntliga examination”Vid den muntliga examinationen i A3 behöver du kunna läsa, förklara och navigera i din egen kod, till exempel hitta var en anropad funktion är definierad. Det är lätt om du skrivit koden själv och blir allt svårare ju mer AI-genererad kod den innehåller. Mikael uppmanar till att öva på detta redan i A2.
Kursledningens insyn och att samarbeta
Section titled “Kursledningens insyn och att samarbeta”- Repon som ligger i kursens studentgrupp, under ditt användarnamn enligt anvisningarna, kan kursledningen se. Det är en fördel vid handledning. De ser bara det som är pushat, aldrig din lokala kod, och de tittar inte i din privata grupp.
- Det går utmärkt att ställa frågor om examinationsuppgifter, på handledning och på Zulip, precis som om vilken annan uppgift som helst.
- Att diskutera uppgiften med andra studenter är också okej och uppmuntras. Både Mats och Mikael hade själva gett ledtrådar snarare än färdiga lösningar, så att kamraten får “aha”-upplevelsen på egen hand. Den som redan kan lär sig ännu mer av att förklara för andra.
Torsdag med frågestund och livekodning
Section titled “Torsdag med frågestund och livekodning”Torsdagen i kursvecka 4 började med en frågestund om ActionHub och pipelines, om hur man blir bättre på att lösa uppgifter på egen hand och om AI-kodkomplettering i VS Code. Därefter löste Mikael övningsuppgiften Knivskarp HTML live, steg för steg, från små körbara bitar och riktade testkörningar till vakter för felaktiga argument och ett exempel på att kasta och fånga undantag.
Om passet
Section titled “Om passet”Torsdagens pass i kursvecka 4 hölls av Mats och Mikael tillsammans och bestod av två ungefär lika långa delar. Den första var en frågestund om ActionHub, VPN och pipelines, om hur man blir bättre på att lösa uppgifter på egen hand, om AI-kodkomplettering i VS Code och om hur mycket man behöver kunna utantill. I den andra delen löste Mikael övningsuppgiften Knivskarp HTML live, med Mats som kommentator.
ActionHub, VPN och en röd pipeline
Section titled “ActionHub, VPN och en röd pipeline”- En fråga gällde guiden för examinationsuppgiften i slutet av kursvecka 3, som frågeställaren upplevde som tom. Den innehåller instruktionerna för att komma igång med A2. Det vanligaste misstaget är att man glömmer att gå in i ActionHub och skapa sina GitLab-resurser för uppgiften. Upplever du instruktionerna som otydliga vill Mats gärna veta det, så att han kan skriva om dem. Instruktionerna om SSH skrevs till exempel om efter synpunkter förra veckan.
- ActionHub nås bara via VPN (eduVPN). Mats startar VPN direkt när han jobbar hemifrån. Mikael slår bara på det när han behöver det, eftersom det kan ställa till det för annat, som Zulip och kurswebbplatsen. Som student i den här kursen är ActionHub troligen det enda som kräver VPN.
- Får du ett rött kryss vid din första commit i A2 beror det sannolikt på att du skapade repot medan Mats ändrade i uppsättningen dagen innan. En ny commit och push startar pipelinen igen.
- Ett tiotal studenter hade inte verifierat sitt GitLab-konto, vilket också hindrar pipelinen från att köras. Verifieringen sker via en länk i ett mejl till studentadressen, men Mats har nu verifierat alla aktiva konton manuellt.
- Kommer du inte igång med VPN eller ActionHub alls, skriv på Zulip. Sådant löses enklast med skärmdelning, inte i ett gemensamt pass.
“Jag förstår lösningen, men kommer inte på den själv”
Section titled ““Jag förstår lösningen, men kommer inte på den själv””En inskickad fråga beskrev en känsla många känner igen: koden är begriplig när man ser den, men det är svårt att komma på lösningen själv. Är det normalt? Ja, helt normalt, svarar både Mats och Mikael. En färdig lösning ser logisk ut i efterhand, men det hjälper inte den dag man själv sitter framför en tom fil.
Det korta svaret är erfarenhet. Det handlar dock inte om att memorera lösningar, utan om att hitta ett lämpligt första steg och skriva så lite kod som möjligt för att komma framåt. Mats tipsar om papper och penna: lös problemet innan du sätter dig vid tangentbordet. Har du inte löst problemet själv först får du två okända att hantera samtidigt, problemet och hur man uttrycker lösningen i JavaScript.
AI-kodkomplettering i VS Code
Section titled “AI-kodkomplettering i VS Code”- En student undrade om det är meningen att man ska trycka Tab när VS Code föreslår färdig kod. Rådet är att trycka Esc i stället, så länge du inte med en snabb blick kan avgöra om förslaget är rätt. Både Mats och Mikael rekommenderar att du stänger av den AI-baserade kodkompletteringen (t.ex. GitHub Copilot). Den vanliga rullgardinslistan med förslag på variabelnamn och liknande är däremot ofarlig och kan spara lite skrivande.
- En annan student slår av och på Copilot med ett kortkommando för att få tänka själv först. Det är ditt eget ansvar hur du lär dig bäst. Märker du att du bara trycker Tab och tycker att du förstår utan att kunna skriva koden själv har du passerat en gräns. Då är det dags att stänga av.
- Mats erfarenhet är att de studenter som tog sig igenom första året på det sättet inte finns kvar i årskurs två. Om tre år ska du kunna bedöma om kod som ett hjälpmedel skrivit är bra eller dålig. Du måste vara bättre än hjälpmedlet.
- Hans rekommendation är att ha AI-assistenten i ett separat program vid sidan om, där du samtalar om din kod, i stället för ett tillägg som gör ändringar direkt i koden. En student berättade om att ha installerat öppen källkodsversionen av VS Code (Code - OSS) på Linux, som saknar de inbyggda AI-funktionerna. Behöver du hjälp att stänga av dem, fråga på Zulip.
- Att det känns jobbigt ibland är en del av poängen. Det är ofta då man tar de viktiga stegen framåt.
Behöver man kunna alla array-metoder utantill?
Section titled “Behöver man kunna alla array-metoder utantill?”Nej. Mikael slår upp dem på MDN varje gång (“mdn js array” i sökfältet, sedan menyn till vänster).
Det viktiga är att veta vad som är möjligt: plocka ut ett element, lägga till och ta bort i början
eller slutet, sortera, och så vidare. De exakta namnen (push, pop, shift, unshift, slice,
at, with…) fastnar med tiden när du använt dem tillräckligt många gånger. Samma kunskap gäller
för alla språk, bara referensmanualen byts ut.
Muntlig examination
Section titled “Muntlig examination”Du får ha med dig vilka hjälpmedel du vill, men frågorna handlar om förståelse, inte om att komma ihåg metodnamn. Examinationsuppgiften anger vilka kursveckor frågorna täcker. Eftersom examinationen är muntlig anpassar examinatorn frågorna efter studenten, ur ett stort frågebatteri: grundläggande frågor när det gäller att avgöra om kraven för godkänt är uppfyllda, svårare frågor för den som visar att den kan mer. Examinatorn kan också förtydliga och ge exempel under samtalet. Har du gjort övningsuppgifterna och förstår din inlämnade examinationsuppgift är du väl förberedd. Det här är ingen kurs där man kan plugga in allt de sista tre veckorna.
Livekodning: Knivskarp HTML
Section titled “Livekodning: Knivskarp HTML”Mikael valde övningsuppgiften Knivskarp HTML, en uppgift på träningsnivå. Han hoppade medvetet över
problemlösningsfasen, som fick mycket tid förra torsdagen, och berättade att han läst igenom
uppgiften i förväg. Han forkade uppgiften till sin egen GitLab-grupp, klonade den, gick in i
katalogen med cd och öppnade VS Code med code .. Uppgiften går ut på att implementera fyra
funktioner i src/shaverSharp.js som bygger HTML-strängar.
Första steget var att, som Mats visade i tisdags, kommentera bort allt i app.js och bara skriva ut
något eget. Går npm start att köra utan att något kraschar vet man var man står. Sedan avkommenterade
han anropen i app.js ett par rader i taget.
createBeginTag och createEndTag
Section titled “createBeginTag och createEndTag”Det första anropet skrev ut undefined. Funktionen hade ännu ingen return-sats. Mats poängterar
senare att en JavaScript-funktion alltid returnerar ett värde: saknas return blir det
undefined. Mikael loggade parametern för att övertyga sig om att han var på rätt ställe och byggde
sedan taggen stegvis, med en variabel som först sattes till en tom sträng och sedan fylldes på med
+=. Resultatet blev stökigt, men det fungerade:
export function createBeginTag(tagName) { let startTag = '' startTag += '<' + tagName + '>' return startTag}Mats lyfter fram att konsolutskrifter mitt i koden är ett utmärkt sätt att bygga en bild av hur koden exekveras, och att det är helt i sin ordning att lämna dem en stund. Han hänvisar till Robert C. Martin (“Uncle Bob”) och boken Clean Code, som används i en kurs i årskurs två: få det först att fungera, sedan kan du återvända och göra det snyggt. Snyggare betyder då att koden ger samma resultat men är lättare att läsa.
Det var precis vad Mikael gjorde med createEndTag. Efter att den fungerade tog han bort den onödiga
tomma strängen och sedan variabeln helt, tills bara en rad återstod:
export function createEndTag(tagName) { return '</' + tagName + '>'}Han övervägde en mallsträng (`</${tagName}>`) men nöjde sig med konkateneringen. Det är en
smaksak.
Köra en delmängd av testerna
Section titled “Köra en delmängd av testerna”npm run test:run kör alla tester en gång, men sammanfattningen hamnar längst upp och kräver
scrollning. npm run test:match createBeginTag kör bara de tester vars namn matchar strängen och
hoppar över resten. Mikael påpekar att det blir extra värdefullt i A2 med dess stora mängd tester.
Han kombinerar två sätt att kontrollera koden: egna anrop i huvudprogrammet (npm start) och
testerna.
Glöm inte npm install innan du kör testerna, vilket Mikael själv glömde först.
createElement och det självstängande elementet
Section titled “createElement och det självstängande elementet”createElement återanvänder de två tidigare funktionerna: starttagg, textinnehåll och sluttagg.
Prettier la ihop Mikaels uppdelade rader till en, eftersom raden fick plats inom den tillåtna
radlängden. Både Mats och Mikael tycker att radlängd och radbrytningar mest är en smaksak, men
påpekar att det är lint- och formateringsreglerna (npm run lint, npm run format) som gäller, inte
personlig smak.
När Mikael körde npm run test:match createElement misslyckades testet creates a self-closing
element when no text content is provided. Utan textinnehåll ska createElement('img') returnera
<img />. Han lade till en if-sats för specialfallet, och felutskriften från testet visade till och
med att det saknades ett mellanslag före />.
Mats kommentar: koden löser problemet, och att lösa problemet kommer först. Men i Mikaels lösning byggs hela elementet först och skrivs sedan över om textinnehållet saknas. Det är värt att återvända till en sådan lösning när den fungerar, i stället för att rusa vidare till nästa uppgift. Ett alternativ är att hantera specialfallet först och bara bygga det fullständiga elementet när det finns textinnehåll.
createElements: en array av objekt
Section titled “createElements: en array av objekt”Sista funktionen tar en array av objekt med egenskaperna tagName och textContent. Objekt är
egentligen nästa veckas ämne, så Mikael tar sig igenom dem utan att gå in på detaljer.
console.table(elementData)skriver ut arrayen som en tabell med index och egenskaper, ett smidigt sätt att få en överblick över mer komplex data.- Han valde en
for...of-loop, menforellerfor...inhade också gått. Vilken loop man väljer spelar inte så stor roll. - För varje objekt anropas
createElement(element.tagName, element.textContent)och resultatet läggs till en resultatsträng som till sist returneras.
Ett test misslyckades: gracefully handles empty collections or missing arguments by returning an
empty string. Mikael lade till två vakter (guard clauses) i början av funktionen: returnera en
tom sträng om arrayen är tom (elementData.length === 0), och likaså om argumentet inte är en array
alls (Array.isArray()). JavaScript har inga typer för parametrar, så JSDoc-kommentaren kan säga
“array”, men du vet aldrig vad anroparen faktiskt skickar in. Det kan till och med vara ingenting
alls. Mats påpekar att det är tillåtet i JavaScript att anropa en funktion med färre argument än den
har parametrar, vilket inte går i många andra språk. I ett svagt typat språk behöver man därför ofta
sådana kontroller. Ett annat alternativ är standardvärden för parametrar.
Mikael gjorde också en rättelse i app.js under passet: objekten där använde egenskapen innerHTML
medan uppgiften och testerna använder textContent. En student hade frågat om detta veckan innan.
Kasta och fånga undantag
Section titled “Kasta och fånga undantag”Som avslutning, eftersom undantag är en del av veckans stoff, ändrade Mikael kontrollen med
Array.isArray() till att kasta ett fel i stället för att returnera en tom sträng:
if (!Array.isArray(elementData)) { throw new TypeError('Expects elementData to be an array.')}Anropas funktionen utan argument avbryts programmet med felmeddelandet och en stack trace, som
visar feltypen och exakt vilken fil, rad och kolumn felet kastades på. Det är användbart vid
felsökning. Den andra halvan av felhanteringen är att fånga felet med try...catch på en högre nivå,
till exempel i app.js, och skriva ut error.message. Mikael visade också att man kan kasta ett
fångat fel vidare, och att det ofta är bättre att låta ett fel man inte kan åtgärda gå vidare än att
bara skriva ut det.
Hade det blivit godkänt?
Section titled “Hade det blivit godkänt?”Om koden hade lämnats in som examinationsuppgift hade den blivit godkänd, eftersom testerna går igenom. Men både Mats och Mikael hade kommenterat vissa konstruktioner. Ostädad kod med gröna tester kan i värsta fall leda till en komplettering. Ta dig tid att städa koden innan du lämnar in.
Vilka övningsuppgifter ska man göra?
Section titled “Vilka övningsuppgifter ska man göra?”Du behöver inte göra de röda uppgifterna märkta Utmaning (t.ex. Kulramen) för att klara A2 eller kursen. De är till för den som redan kan grunderna och tycker om kluriga problem. Uppgifterna upp till och med träningsnivå (Grunderna med arrayer, Additionell kopia av array, Sorterad kopia av array, Knivskarp HTML) förbereder dig direkt för A2. Att hoppa över dem sparar ingen tid, snarare tvärtom.
Kör du fast med övningsuppgifterna eller kommer inte igång med A2, skriv upp dig under ämnet Individuell handledning i kursens Zulip-kanal så hör kursledningen av sig.
Stödjande inspelningar
Section titled “Stödjande inspelningar”Exempel - Vilket Unicode-värde
Section titled “Exempel - Vilket Unicode-värde”Kursledningen inleder till viss del med repetition för att förstärka delar som rör funktioner och moduler.
Exempelkoden hittar du på GitLab.Utgångsläget: allt i en sekvens
Section titled “Utgångsläget: allt i en sekvens”Exemplet startar som ett litet, fungerande program: det läser in en textrad och ett index från användaren (via paketet readline-sync) och skriver ut vilket tecken och Unicode-värde som finns på det indexet, tills ett negativt index avslutar programmet. Hela logiken ligger som en enda lång sekvens av satser i app.js – precis det som gör koden svår att testa och underhålla när ett program växer.
Ett första steg mot bättre struktur: identifiera vilka satser som hör ihop, och bryt ut dem till egna funktioner.
Steg 1: bryt ut satser till funktioner
Section titled “Steg 1: bryt ut satser till funktioner”Två tydliga kandidater identifieras: utskriften av hjälptexten och läsningen av ett index. De blir varsin funktion:
const printInstructions = function () { console.log('...')}
const getIndexFromUser = function () { return Number.parseInt(readlineSync.question('Enter an index (negative value to quit): '))}getIndexFromUser används på två ställen i originalkoden (en gång innan loopen, en gång sist i loopens kropp) – att bryta ut den till en funktion tar bort just den upprepningen. En funktion som getIndexFromUser behöver inga parametrar eftersom den bara returnerar ett värde den själv hämtar in.
Steg 2: samla allt i en main-funktion
Section titled “Steg 2: samla allt i en main-funktion”Med flera funktioner definierade blir det otydligt var exekveringen egentligen börjar. Lösningen är att samla den kvarvarande “lösa” koden i en egen funktion, av tradition ofta kallad main (ett arv från C-liknande språk):
const main = function () { // all kvarvarande kod, inklusive while-loopen}
main()Anropet av main() sist i filen blir den enda platsen exekveringen faktiskt startar – tydligare än att låta lös kod ligga utspridd bland funktionsdeklarationerna.
Steg 3: bryt ut funktionerna till en egen modul
Section titled “Steg 3: bryt ut funktionerna till en egen modul”Fortfarande ligger alla funktioner i samma fil som main. Nästa steg i omstruktureringen är att gruppera de funktioner som hör ihop och flytta dem till en egen modul – samma princip som att gruppera satser i funktioner, bara ett steg upp. En ny fil (namngiven i kebab-case, i linje med Node-modulers namnkonvention) samlar hjälpfunktionerna, och exporterar dem med namngivna exports:
export const printInstructions = function () { ... }export const getIndexFromUser = function () { ... }// osv.import * as UnicodePicker from './unicode-picker.js'
const main = function () { UnicodePicker.printInstructions() // ...}Ett par detaljer som gav verkliga felmeddelanden på vägen: importsökvägen till en egen ES-modul måste innehålla filändelsen (.js) – till skillnad från CommonJS, där det brukar fungera utan. Och en modul utan export default kan inte importeras med ett vanligt import Namn from ... – då krävs antingen namnrymdsimport (import * as Namn from ...) för att få tag i alla namngivna exports samlade under ett gemensamt namn, eller en specifik namngiven import (import { specifikFunktion } from ...) om bara någon enstaka funktion behövs. export default avråds ifrån här – att alltid skriva ut exakt vad som exporteras gör koden tydligare.
Slutresultatet: app.js innehåller bara main, som läses nästan som en innehållsförteckning över vad programmet gör; all den specifika logiken ligger samlad i en egen, namngiven modul.
Lärdomar
Section titled “Lärdomar”Att lägga ett så här litet exempel (ett tjugotal rader) i flera filer och moduler kan kännas onödigt omständigt för just det här problemet – poängen är träningen i sig, eftersom samma disciplin blir avgörande först när ett program vuxit till tusentals rader. Det är för sent att lära sig strukturera kod först då. Detsamma gäller dokumentation: att skriva en funktions JSDoc-kommentar innan man skriver dess innehåll tvingar fram klarhet i vad funktionen faktiskt ska göra, istället för att dokumentationen blir en eftertanke som ofta uteblir helt i tidspress.
Arrayer
Section titled “Arrayer”Att kunna organisera större dataset i listor, arrayer, är mycket kraftfullt. En lång föreläsning på ämnet ligger till grund för dessa delar.
PresentationVarför arrayer?
Section titled “Varför arrayer?”En variabel kan bara hålla ett värde, och en funktion kan bara returnera ett värde. Men mycket av det vi vill programmera handlar inte om enstaka värden utan om samlingar av värden – en lista med vänner, en kundvagn, rader i en handlingslista. Lösningen är en referens till en array eller ett objekt, där själva samlingen kan innehålla hur många värden som helst.
En array är en ordnad lista med värden. Ordnad betyder här att raderna behåller sin inbördes ordning – inte att värdena är sorterade.
Skapa en array
Section titled “Skapa en array”Det rekommenderade sättet är en array-literal med hakparenteser:
const groceries = [ 'mjölk', 'ägg', 'pasta', 'ketchup', 'nudlar', 'havregryn']Varje värde i listan kallas ett element, och elementen numreras från och med 0 – ett 0-baserat index. groceries[4] ger alltså det femte elementet, 'nudlar', inte det fjärde.
Det går också att skapa en array med new Array(...), men det avråds ifrån – konstruktorn beter sig olika beroende på hur många argument som skickas in. new Array(28, 18, 26) skapar en array med de tre talen, men new Array(10) skapar inte en array med värdet 10, utan en array med tio tomma (undefined) element. Array-literalen har inte den fällan.
Alla värden i en array bör vara av samma datatyp. JavaScript tillåter att man blandar typer ([42, 'är meningen med livet', true]), men det är en dålig idé – blir det en samling av olika typer av data hör den hemma i ett objekt istället.
Arbeta med element
Section titled “Arbeta med element”Index används både för att läsa och skriva ett elements värde:
const temperatures = [12.6, 18.7, 9.8, 13.2, 14.4]
console.log(temperatures[3]) // OUTPUT: 13.2temperatures[1] = 4.2 // tilldelar det andra elementet ett nytt värde
console.log(temperatures.length) // OUTPUT: 5length är en egenskap, inte en metod – inga parenteser.
Iterera med for-loop
Section titled “Iterera med for-loop”Att en array har ett 0-baserat index och en känd längd är precis varför for-loopen ofta ser ut som den gör:
let output = ''for (let i = 0; i < temperatures.length; i++) { output += temperatures[i] + ' '}Loopvillkoret ska vara i < length, inte i <= length – längden 5 betyder att sista giltiga indexet är 4. Försöker man läsa ett index utanför arrayen kraschar inte JavaScript (till skillnad från många andra språk) – man får undefined tillbaka istället.
Lägga till och ta bort element
Section titled “Lägga till och ta bort element”De vanligaste metoderna för att ändra en arrays storlek:
push(värde)– lägger till sistpop()– tar bort och returnerar det sista elementetunshift(värde)– lägger till förstshift()– tar bort och returnerar det första elementet
splice() kan lägga till, ta bort eller ersätta element mitt i en array, men används mer sällan.
Värdetyper och referenstyper
Section titled “Värdetyper och referenstyper”Det här är den mest centrala – och klurigaste – delen. Number (och de andra primitiva typerna) är en värdetyp: när en variabel tilldelas en annan variabels värde kopieras själva värdet, och de två variablerna blir sedan helt oberoende av varandra.
let dogAge = 7let catAge
catAge = dogAge // 7 kopieras till catAgecatAge = 3
console.log(catAge) // OUTPUT: 3console.log(dogAge) // OUTPUT: 7 – opåverkadEn array är däremot ett objekt, och objekt är referenstyper. Tilldelningen kopierar inte själva arrayen, bara en referens till den – som att ge ut ett extra koppel till samma hund. Två variabler kan referera till en och samma array:
const numbers = [5, 8, 7, 1, 6]let figures
figures = numbers // figures får en referens till SAMMA arrayfigures[0] = 42
console.log(figures) // OUTPUT: [ 42, 8, 7, 1, 6 ]console.log(numbers) // OUTPUT: [ 42, 8, 7, 1, 6 ] – båda påverkas!Anledningen till att referenser fungerar så här är prestanda: en array kan innehålla hundratusentals värden (tänk en bildfil, pixel för pixel), och att kopiera hela innehållet varje gång skulle vara orimligt dyrt. Att kopiera en referens – i praktiken en minnesadress – kostar i princip ingenting.
Referenser som argument och returvärde
Section titled “Referenser som argument och returvärde”Samma resonemang gäller när en array skickas till eller returneras från en funktion. Skickas en array in som argument arbetar funktionen på samma array som anroparen har, vilket kan ge oönskade sidoeffekter:
const logDoubledUp = function (results) { for (let i = 0; i < results.length; i++) { results[i] *= 2 } console.log(results)}
const scores = [18, 9, 23, 12, 21]logDoubledUp(scores)console.log(scores) // OUTPUT: [ 36, 18, 46, 24, 42 ] – scores har muterats!Vill man undvika det arbetar man på en kopia istället, till exempel med Array.from(), spridningsoperatorn [...array] eller (äldre) .slice():
const logDoubledUp = function (results) { const copy = Array.from(results) for (let i = 0; i < copy.length; i++) { copy[i] *= 2 } console.log(copy)}Sortera en array
Section titled “Sortera en array”sort() utan argument konverterar först elementen till strängar och jämför dem lexikografiskt – vilket ger överraskande resultat för tal (10 hamnar före 2). Ska talen sorteras numeriskt behövs en egen jämförelsefunktion:
const values = [2, 42, 10, 1, 8, 24, 4]values.sort(function (a, b) { return a - b})// OUTPUT: [ 1, 2, 4, 8, 10, 24, 42 ]Fler metoder: forEach, reduce och map
Section titled “Fler metoder: forEach, reduce och map”forEach itererar igenom värdena, reduce reducerar dem till ett enda värde (till exempel en summa), och map skapar en helt ny array genom att transformera varje värde:
const values = [2, 1, 8]
values.forEach(function (value) { console.log(value)})
const sum = values.reduce(function (a, b) { return a + b}, 0) // OUTPUT: 11
const doubledValues = values.map(value => value * 2) // OUTPUT: [ 4, 2, 16 ]Både forEach och reduce tar emot en funktion som argument, vilket gör dem till exempel på det som kallas “higher-order functions”. map-exemplet visar också en arrow function – ett kortare sätt att skriva ett funktionsuttryck på, där function och return kan uteslutas när kroppen bara innehåller en sats.
Undantag
Section titled “Undantag”Redan nu smygs en kort introduktion till undantag in.
PresentationNågot kommer att gå fel
Section titled “Något kommer att gå fel”Även om koden är korrekt utifrån vad man känner till kan en applikation stöta på fel: felaktig indata, ett API som svarar annorlunda än väntat, eller helt enkelt ett misstag i koden. Det här blir extra tydligt så fort en applikation tar emot data utifrån – från en användare, ett nätverksanrop eller en extern tjänst – för då vet man aldrig med säkerhet vad som faktiskt kommer in.
const name = 'Lovelace'name = 'Hopper' // TypeError: Assignment to constant variable.console.log(name) // körs aldrigNär ett exekveringsfel inträffar kastas ett undantag, och exekveringen av programmet avbryts omedelbart där felet uppstod – satsen efter felet körs aldrig.
Vad är ett undantag?
Section titled “Vad är ett undantag?”Ett undantag är inget annat än ett objekt som representerar felet. JavaScript har flera inbyggda feltyper som används vid olika sorters fel: Error, EvalError, InternalError, RangeError, ReferenceError, SyntaxError, TypeError och URIError. I egen kod är det oftast Error och TypeError man kastar.
Kasta undantag
Section titled “Kasta undantag”Utöver att JavaScript själv kastar undantag kan man som programmerare aktivt kasta ett eget, med det reserverade ordet throw. Ett felobjekt skapas med new och tar oftast ett meddelande som argument:
const getDigitSum = function (value) { if (typeof value !== 'number') { throw new TypeError('The argument passed must be a Number.') } // summera siffrorna och returnera summan}Poängen med att kontrollera indata och kasta ett tydligt fel direkt är dels att undvika konstiga följdfel längre in i koden, dels att en funktion i praktiken kan anropas med vilket argument som helst – det finns ingen garanti för att den som anropar skickar in rätt typ.
Felobjektet har egenskaperna name (vilken feltyp) och message (det egna meddelandet), på samma sätt som vilket annat objekt som helst.
Fånga undantag
Section titled “Fånga undantag”Kod som riskerar att kasta ett undantag placeras i ett try-block. Kastas ett undantag där hoppar exekveringen direkt till catch-blocket, som får tillgång till felobjektet och kan hantera det – till exempel logga ett mer användarvänligt meddelande istället för att låta hela applikationen krascha med en teknisk stacktrace. Ett eventuellt finally-block körs alltid, oavsett om ett fel kastades eller inte.
try { const result = getDigitSum('This is not a number') console.log(`The sum of the digits is ${result}.`)} catch (err) { console.error(err.message)} finally { // körs alltid}try/catch/finally kan kombineras som try-catch, try-finally eller alla tre tillsammans. Blir det inget fel i try-blocket exekveras inte catch-blocket – men finally körs ändå.
Så länge koden själv har full kontroll (till exempel att bara skicka in tal man redan vet är tal) behövs inget try/catch. Det blir nödvändigt först när koden gör saker den inte kan garantera lyckas – och det tydligaste exemplet är nätverksanrop över internet, där en kabel kan vara av eller en server nere. Det är ett ämne som återkommer längre fram i kursen.
Läsanvisningar
Section titled “Läsanvisningar”Under läsanvisningar hittar du veckans kapitel som ska läsas i kurslitteraturen. Planera upp och dela upp läsningen under veckan.
Övningar
Section titled “Övningar”Under Övningsuppgifter hittar du övningsuppgifter som det är lämpligt att du arbetar med under veckan.
Seminarier + individuell handledning
Section titled “Seminarier + individuell handledning”Vid det här laget är du bekant med handledningskonceptet. Ett tips är att de studenter som lyckas bäst på utbildningen är också de studenter som är aktiva på handledningstillfällena!
Examinationsuppgift A2
Section titled “Examinationsuppgift A2”Examinationsuppgift A2 finns publicerad och denna vecka bör du i alla fall läsa igenom uppgiftsbeskrivningen och kanske få igång uppgiften lokalt på din dator (se Kursvecka-03). Det räcker att du börjar arbeta på uppgiften under nästa vecka, kursvecka 05, men det skadar inte om du börjar redan i denna veckan.
Utmaningar
Section titled “Utmaningar”Antalet utmaningar minskar i takt med att övningsuppgifternas komplexitet ökar.
Studiefrågor
Section titled “Studiefrågor”Här är ett antal frågor som du kan försöka besvara och diskutera tillsammans med en AI-assistent. Tveka inte att lyfta någon av frågorna till handledningen för att fortsätta diskussionen med lärare och studiekamrater.
- Förklara grunderna i konstruktionen array i JavaScript.
- Vilka är de vanligaste inbyggda metoderna som man behöver lära sig när det gäller arrayer?
- När man jobbar med arrayer så är koden ibland funktionellt skriven och ibland mer procedurell, vad är skillnaden i de båda tankesätten?
- Finns det något särskilt jag bör tänka på om jag gör ett program som jobbar med arrayer och nummer?
- Vill du ge ett exempel på hur man kan använda undantag tillsammans med arrayer och nummer?
Här är en utskrift från hur det kan se ut när frågorna ovan diskuterats med en AI-assistent.
Här följer tips till hur du kan prioritera bland kursmaterialet för att komma igång med veckan.
- Både utmaningar och övningsuppgifterna är bra träning för att hjälpa dig att lära dig olika konstruktioner i JavaScript. Se till att kombinera praktisk programmering och felsökning tillsammans med att du tittar på föreläsningar och litteraturen.
- Denna veckan har fokus på arrayer, så se till att du lär dig grunderna i arrayer (och lite till). Du kommer att ha stor nytta av arrayer i A2.
- Börja med A2, det är mycket att läsa och om det finns någon metod som du kan börja bygga så gör det. Det är många enhetstester som skall passeras så ta ett antal varje vecka.
