Grunderna i JavaScript-programmering

Från Webbling
Version från den 31 oktober 2020 kl. 14.32 av PGJ (diskussion | bidrag)
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 kanske du vill 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åk 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 matematik. 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 mer 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 koden 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 bara 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å. Men liksom när man försöker kommunicera med en hund eller en tvååring så kan det vara svårt att förklara 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).

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 en rad 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 uppmanas att 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...)

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 fort 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 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, så 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 och vi kan stoppa när vi är ett steg under talet vi ska testa.
  • Vi uttrycker det med lite pseudokod:
 Sätt nämnare = 2
 Medan nämnare är mindre än tal
    Om tal / nämnare = jämt
     Tal är ej primtal
   Annars
     Öka nämnare med 1
  • Vi kanske skapar ett flödesdiagram

PrimtalFlowchart.png

  • 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 ifrån sådant vi inte fattar, 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 man gör 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 runt 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.

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 av 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!

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. Vi kommer att se så är det rätt vanligt inom programmering att saker har flera olika namn. Vi i datorvärlden en tendens att använda svengelska termer för saker och ting. Detta gäller extra mycket för oss programmerare!

Satser

Uttrycket sats kommer ifrån matematikens och logikens värld. En sats är dä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 ett ";"-tecken. Så gott som alla programrader ska avslutas på detta vis. Det finns ett fåtal undantag där man inte ska avsluta en programrad med ”;”. Vi återkommer till dessa längre fram...

Det är ett vanligt fel att man glömmer ett ";"-tecknet och då kommer kanske programmet inte att kunna köras korrekt. Vanligtvis är avsaknaden av ";" en av de första saker du ska kontrollera då ditt program inte vill köra. Här är dock JavaScript mindre känsligt än andra språk i C-familjen. Faktum är att man i många fall kan utelämna ";"-tecknet. Det är dock inte att rekommendera, det skapar bara dåliga ovanor att göra detta.

Kodblock; { och }

Kodexemplet där vi kontrollerade om något är ett primtal innehöll antagligen några tecken som du inte är helt van vid att använda. Jag tänker främst på "{" 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å språken 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 ifrån 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 programmeringsproblem går att reducera till lagring, upprepning och val. Faktum är att matematikern Alan Turing bevisade 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