Grunderna i JavaScript-programmering

Från Webbling
Hoppa till: navigering, sök

Här kommer vi att gå igenom programmering från scratch, så om du har lite kunskaper inom området behöver du antagligen bara behöva att snabbskumma igenom de första aktiviteterna i denna sektion...

Om du kan något annat programmeringsspråk i C-familjen (t.ex. C, C++, C# eller Java) kan du redan mycket av grunderna i JavaScript. Dessa språks grunder påminner mycket om varandra. Dock finns det en del skillnader, såsom hur man deklarerar variabler och dylikt. Det bör dock inte vara alltför svårt att sätta sig in i skillnaderna. Däremot finns det en hel del skillnader man måste lära sig om man vill skriva riktigt optimal kod.

Vad är programmering?

Programmering är en typ av problemlösning där man tar fram en ”steg för steg”-beskrivning för hur datorn ska lösa ett problem eller en klass av problem. Datorerna är egentligen rätt dumma och kan enbart utföra väldigt grundläggande uppgifter, typ den enklaste matematiken. Däremot är datorer extremt snabba (och relativt tillförlitliga). På grund av denna snabbhet kan man skapa problemlösningar som i grund och botten är uppbyggda av tonvis av små, enkla funktioner, som stegvis utför allt mer komplexa uppgifter. Oavsett i vilket programmeringsspråk vi programmerar, så kommer vår kod att översättas till något som datorn kan fatta och utföra. I slutändan är det alltid maskinkod, dvs processorns egna språk, som utför arbetet. Varje kodrad som återfinns i ett program kan resultera i en mängd operationer som måste genomföras för att uträtta det som kodraden beskriver. Till och med när man kör de enklaste programmen, så utför datorn myriader av operationer.

Datorn har ett väldigt litet antal kommandon som den klarar av att utföra. Varje programmeringsspråk har en uppsättning ord och regler som avgör vad språket "fattar" och kan utföra. Det är sällan mer än ca 100 grundfunktioner som finns i ett programmeringsspråk. När vi ska lösa våra problem måste vi formulera lösningar som enbart använder sig av dessa ord. 100 ord är inte så mycket, det är färre ord än en hund eller en tvååring kan förstå. Liksom när man försöker kommunicera med en hund eller en tvååring så kan det vara svårt att formulera lösningen till ett komplext problem enbart genom att använda sig av det starkt begränsat vokabulär man har att tillgå. Datorn har dock en fördel i jämförelse med hundar och små barn, den utför exakt vad du beordrar den att göra. Den gör vare sig mer eller mindre än det du säger åt den att göra (hur dumma eller felaktiga dina order än må vara).

I skrivandets stund har faktiskt JavaScript endast 46 "grundord". Dock har de flesta språk även så kallade standardbibliotek som innehåller extra funktionalitet. Denna extra funktionalitet består oftast i sånt som bara används för vissa typer av programmering. Det kan vara t.ex. filhantering för att skriva och läsa data. Det kanske inte alla program kräver och därför ligger det i ett bibliotek som vi kan inkludera. Allt eftersom vi programmerar utökar vi även vilka "ord" som finns att tillgå i vår kod.

När man programmerar går man igenom flera faser. Man börjar med att analysera det problem man vill lösa. Man försöker, om möjligt, att reducera problemet till flera, enklare delproblem. Därefter hittar man på lösningsförslag till varje delproblem och försöker sedan att kombinera dellösningarna till en komplett lösning som genomför allt man förväntade sig.

Programmering påminner lite om hur man löser vissa problem i matematiken, t.ex. såna där problem där "Lisa har tre äpplen, Per har två skohorn...". Man vet vad man har för startvillkor och man vet var man vill hamna – det svåra är att hitta vägen ifrån A till B. Ibland måste man ta en liten avkrok på vägen och klara av några delproblem, som förhoppningsvis kan ge ledning till hur man ska komma fram till slutlösningen. Även det som låter väldigt enkelt, kan bli krångligt och komplext när man ska uttrycka det som kod. Gillar du att lösa problem är programmering den ultimata utmaningen!

I tidiga faserna av programmering jobbar man ofta på papper. Man kanske ritar upp problemet, t.ex. med flödesdiagram. Ett annat sätt för att beskriva lösningsförslag är att använda sig av så kallad pseudokod. Pseudokod är ett mer formaliserat sätt att sätta ord på programmeringslösningar. Det är en blandning av vanligt, mänskligt språk och programmeringsspråk. Det finns ingen standard för hur pseudokod ska se ut. Man skriver mer eller mindre i klartext hur lösningen ska fungera, steg för steg.

Algoritm

Problemlösningar av typen steg-för-steg, kallas för algoritm. Algoritmer känner du säkert igen ifrån matematiken. Den vanliga metoden för att lösa en andragradsekvation, PQ-formeln, är ett exempel på en algoritm. När man använder den formeln jobbar man steg för steg för att på ett generellt sätt lösa en andragradsekvation. Andra vardagsexempel på algoritmer kan vara matrecept, bygginstruktioner (typ sådana man får med IKEA-möbler) eller liknande.

I en algoritm är viktigt att man utför de olika stegen i rätt ordning, annars kommer resultatet inte att bli korrekt. Vanligtvis utför man stegen i en algoritm ett efter ett. Man börjar i toppen och går framåt rad för rad. Detta kallas att arbeta sekventiellt eller synkront. De flesta enkla datorprogram fungerar på detta sätt.

Ibland kan man ha en instruktion som säger att man ska hoppa över några rader om något speciellt villkor är uppfyllt. Detta kallar man ibland för selektion, dvs man väljer ut vilka rader som ska köras.

Det är också vanligt förekommande att man vill upprepa en, eller flera, rader i en algoritm, kanske upprepar man tills något villkor är uppfyllt. Detta kallas för iteration, eller upprepning.

Detta där är grundstenarna i programmering, men vi behöver en sak till. För att kunna beräkna saker måste vi även ha lagring. Vi måste på något vis kunna spara undan våra beräkningar.

Alla dessa begrepp sammantagna är grunden till programmering; lagring, sekvens, selektion och iteration. Har vi tillgång till dessa saker kan vi beräkna allt! (I alla fall allt som går att beräkna...) Detta är något som bevisats av Alan Turing och Alonzo Church. Vi brukar kalla språk som har alla dessa finesser för turingkompletta.

Programmering är oftast en iterativ process, där man jobbar med stegvis förfining. Vilket är ett halvkrångligt sätt att säga att man gör saker om och om igen, men man försöker förbättra resultatet varje gång. Ett exempel på det kan vara att man i första skedet skapar en algoritm som gör det den ska, utan att bry sig om hur snabbt algoritmen utför sitt arbete. I nästa iteration, eller upprepning, försöker man förbättra algoritmen så att den går snabbare. På så vis förbättrar man sitt program stegvis.

Exempel: Är ett heltal ett primtal?

Låt säga att vi ska kontrollera om ett heltal är ett primtal. När man ska lösa det problemet, kanske man går igenom en process som påminner om följande:

  • Först måste vi ta reda på vad ett primtal är. På Wikipedia finns den här definitionen:

"Ett primtal är ett heltal p, som är större än 1 och som bara är jämt delbart med ±1 och ±p".

  • Om man funderar lite kommer man fram till att man ”bara” behöver prova om talet är jämt delbart med något mellan 2 och (talet - 1). Ettan ska vi skippa eftersom allt är jämt delbart med 1. Vi kan stoppa när vi är ett steg under talet vi ska testa. För ett tal är ju alltid jämt delbart med sig själv.
  • Vi uttrycker det med lite pseudokod:
 Sätt nämnare = 2
 Medan nämnare är mindre än tal
    Om tal / nämnare är jämt
        Tal är ej primtal
    Annars
        Öka nämnare med 1
  • Vi kanske skapar ett flödesdiagram

  • Nu kan vi omvandla pseudokoden till JavaScript-kod
function primtal(tal) {
  let nämnare = 2;

  while( nämnare < tal ) {
    if( tal % nämnare == 0 ) {
      return false;
    }
  }

  return true;
}

En relativt ineffektiv lösning (och lite buggig)…

Även om vi inte kan programmering så bra ännu, så går det faktiskt att läsa vad som händer i koden ovan. Om vi bortser från sådant vi kanske inte fattar just nu, som t.ex. let och % (den senare ger oss resten efter en heltalsdivision), ser vi att koden är rätt så lik vår pseudokod, med den stora skillnaden att sakerna står på halvengelska.

Funktioner, metoder, osv

Vad vi skapade i föregående sektion är en funktion. Dessa fungerar ungefär som i matematiken när man skapar funktioner av typen f(x). Funktioner är ett sätt på vilket man kan skapa små dellösningar. Man skriver kodsnuttar som man sedan kan kombinera till större lösningar. Man skulle kunna säga att man utvidgar programmeringsspråket med just de specifika finesser som man själv behöver. Vi nämnde tidigare hur datorspråkens grundvokabulär oftast bara består av mindre än 100 ord. Varje gång man skapar en ny funktion (eller liknande) så utökar man detta vokabulär. Desto fler funktioner vi skapar, desto enklare blir det att beskriva den lösning man är ute efter. Allteftersom vi kodar skapar vi alltså ett språk som är mer anpassat till det vi vill lösa för tillfället.

I många fall går funktionerna även att återanvända när man skriver andra program. Som programmerare jobbar man ständigt på att utvidga sin verktygslåda med lösningar, algoritmer och funktioner. Det är alltså bra att försöka hålla sina funktioner så generella som möjligt, så att de går att återanvända. Varje gång du skapar en funktion som är återanvändbar, finns chansen att du besparar dig själv en massa onödigt arbete i framtiden! När du kommer ut i arbetslivet kommer säkerligen din arbetsplats att ha en uppsättning med bibliotek som används inom företaget. Självklart finns det även många bibliotek som du kan ladda ned från nätet för att få extra funktionalitet till dina program.

Kärt barn har många namn; det är också vanligt att kalla funktioner för metoder, rutiner eller subrutiner, osv. Även om det skiljer lite mellan den korrekta definitionen på hur man ska använda de olika namnen, så kan man säga att alla är godtagbara. Oavsett vilket namn du använder bör programmeringskunniga fatta vad du menar. Inom programmering är det rätt vanligt att samma saker har lite olika namn. Inom datorvärlden har vi även en tendens att använda svengelska termer för saker och ting. Detta gäller definitivt för oss programmerare!

Satser

Uttrycket sats kommer ifrån matematikens och logikens värld. En sats är en utsaga som kan prövas. Vissa satser kan man använda för att beräkna saker - kanske du stött på binomialsatsen. Inom programmering är en sats en komplett utsaga som kan utföras. Lite förenklat kan man säga att varje rad i ett JavaScript-program är en sats (ibland delar man upp en sats på flera rader). Ett exempel på en sats i vår primtals-funktion är;

let nämnare = 2;

I den satsen skapar vi en variabel och vi ger den namnet nämnare samt att vi tilldelar den värdet 2. Varje sats genomför oftast någon "enkel" deluppgift/delsteg i vår algoritm. Man kan självklart kalla detta för mycket annat än sats, t.ex. kodrad, programrad, uttryck, osv.

För att indikera var en sats avslutas skriver man oftast ett ";"-tecken. Så gott som alla programrader ska avslutas på detta vis. I modern JavaScript är inte ";"-tecknet helt nödvändigt. Istället kommer JavaScript att se en avslutad rad som en komplett sats. I de flesta fall är det dock enklare att se var satsen avslutas genom att skriva ett ";"-tecken.

Kodblock; { och }

Kodexemplet med primtal innehöll antagligen några tecken som du inte är helt van vid att använda. Det gäller nog främst "{" och "}". Dessa är vanligt förekommande i de många programmeringsspråk. De kallas för klammerparenteser.

Klammerparenteser kan också heta klammer, måsvingar, braces, curly braces, osv. De senare är de engelska namnen på tecknen. Vi programmerare kör ofta med engelska eller snarare svengelska uttryck, vilket är rätt naturligt då de flesta programmeringsspråk är baserade på engelska. Engelskan är förstås programmeringens "modersmål", då de flesta språk baseras på engelska ord och så gott som all dokumentation först och främst (och kanske enbart) är skrivna på engelska.

Vad man än kallar klamrarna, så har de en mycket speciell betydelse i JavaScript (och många andra programmeringsspråk). De används för att definiera ett kodblock. Det vill säga man har ett antal sats-rader som ska hänga samman som en enda stor sats och som ska utföras tillsammans (de körs dock inte samtidigt, utan de utförs fortfarande sekventiellt). Det kan vara kod som enbart ska köras när något speciellt villkor är sant (en så kallad if-sats) eller kod som ska upprepas flera gånger (en så kallad slinga eller loop). Lägg märke till att block inte avslutas med ett ";"-tecken.

Mer om primtalsexemplet

I vår kodsnutt hade vi även exempel på något av det mest grundläggande som behövs för programmering, nämligen variabler. Dessa används för att lagra värden. Speciellt viktigt är att vi kan lagra undan resultat och delresultat i våra beräkningar. Vi återkommer till variabler alldeles strax.

I koden hade vi även exempel på några av de mest centrala begreppen i programmering; upprepning och val. Eller för att använda fackspråk; iteration och selektion. Upprepning gör att vi kan köra en bit av vår programkod flera gånger. Medan val möjliggör att vi kan styra programflödet och köra olika kodbitar beroende på diverse villkor.

De flesta programmeringsproblemen går att reducera till lagring, upprepning och val. Som vi konstaterade tidigare så bevisade Alan Turing att just dessa grundkoncept är vad som krävs för att kunna beräkna allt som är beräkningsbart.

Nästa aktivtet

Att skriva läsbar kod