Functies

Wat is een functie en waar zijn ze goed voor.

Een stoel heeft een functie, daar kun je op zitten. De functie van een stoel is anders dan die van een punaise. Als je iets op het prikbord op wil hangen zoek je een punaise en wel om de functie om iets op te hangen. Vraag je om een punaise dan weet je omgeving dat je waarschijnlijk iets vast moet prikken. Kortom een punaise heeft een functie en die kun je inzetten. Een stoel heeft ook een functie en die zet je ergens anders voor in.

In de vorige hoofdstukken zijn er hier en daar al wat functies de revue gepasseerd waaronder: document.getElementById(..), Number(..), isNaN(..), charAt(..). Deze functies voerden iets voor je uit wat je op dat moment nodig had. Deze functies zijn onderdeel van een groot aantal standaard functies in javascript. Je kunt ook zelf functies maken. Ook dat heb je al gedaan. Je hebt namelijk bij de formulieren functies gemaakt die op een event (gebeurtenis) reageerde. In dit hoofdstuk gaan we dieper in op wat voor soort functies er zijn en hoe je die slim in kan zetten om je code overzichtelijker te houden of om veelgebruikte code uit te laten voeren.

Aan het einde van dit hoofdstuk weet je :

  • weet je verschillende functies te benoemen;
  • kun je verschillende standaard functies weten te vinden en toe te passen;
  • kun je zelf ook functies maken;

Bekijk de video. Deze video biedt een basis voor de rest van dit hoofdstuk.


Indeling functies en standaard functies

In onderstaande tabel is een indeling gemaakt van mogelijke functie vormen en enkele standaard functies als voorbeeld. Klik op het woord functie bij de voorbeelden om meer uitleg te krijgen.
Zonder argumenten:
Een functie doet wat zonder gegevens nodig te hebben.
Met argumenten:
Een functie doet alleen maar wat met de juiste gegevens.
Zonder teruggave:
Een functie voert iets uit en geeft geen informatie terug aan de gebruiker
<HTMLElementObject>.click()
Functie forceert een mouse click event op het betreffende object.
<date>.setTime(millisec)
Functie zet de tijd van een date object naar de gegeven miliseconden
Met teruggave
Een functie voert iets uit en geeft informatie terug aan de gebruiker
<string>.toUpperCase()
Functie maakt een nieuwe string en vult die met een hoofdletter versie van de string.
Math.random()
Functie berekent een toevalsgetal tussen 0 en 1 en geeft deze terug.
document.getElementById('id van html tag')
Functie zoekt object met id in het document en geeft die terug
Math.max(a,b)
Functie berekent de maximale waarde van a en b en geeft deze terug na aanroep.

Er zijn vele standaard functies binnen javascript. w3schools is een goede bron. Wil je echt alles over javascript weten dan biedt de javascript bible uikomst.

We zullen nu een aandacht besteden aan een tweetal bibliotheken die veel gebruikt worden in bewerkingen op tekenreeksen en getallen. In het hoofdstuk Array's bekijken we nog de bij array's behorende bibliotheek.

Math De Math bibliotheek bevat een groot aantal rekenfuncties voor getallen. Voor onderstaande opdrachten heb je deze bibliotheek nodig. Maak een html document met een formulier met twee invoervelden en een uitvoerveld. Voeg voor iedere opdracht een nieuwe button toe. Je hoeft je in deze opgaven niet bezig te houden met foutafhandeling.
Opdrachten
  1. Laat twee getallen invoeren en bepaal met een Math functie welke de grootste is.
  2. Vermenigvuldig beide getallen met PI en bepaal respectievelijk de cosinus en de sinus van de waarden na vemenigvuldigen.
  3. Rond het eerste getal af naar boven het tweede naar onder.
  4. Bepaal het absolute verschil met de afgeronde waarden van beide getallen.
String

De String bibliotheek bevat een groot aantal functies en eigenschappen waarmee informatie over een tekenreeks kan worden verkregen of waarmee de tekenreeks kan worden gemanipuleerd. In de bovenstaande tabel zijn er al een paar te vinden. Voor onderstaande opdrachten heb je deze bibliotheek nodig. Maak een html document met een formulier met één invoerveld en en een uitvoerveld. Voeg voor iedere opdracht een nieuwe button toe. Je hoeft je in deze opgaven niet bezig te houden met foutafhandeling

Opdrachten
  1. Substring is een functie waarmee je een deel van tekststring kan selecteren. Zorg ervoor dat de ingevoerde tekenreeks in twee gelijke stukken (bij oneven lengte eerste deel 1 groter) wordt gesplitst die op twee regels in het uitvoervlak worden getoond. Gebruik de length eigenschap en Math.floor().
  2. Zelfde opgave als hierboven maar nu de stukken in de omgekeerde volgorde aan elkaar plakken. b.v. "schoolfeest" -> feestschool
  3. Toon alleen dat deel van de tekenreeks dat na de eerste "a" komt. b.v. aardappel -> ardappel
  4. Toon alleen dat deel van de tekenreeks dat na de laatste "a" komt. b.v. aardappel -> ppel
  5. Bepaal of het woord "seks" in de tekenreeks voorkomt. Meld dat je een beschaafde site bent waarin dit soort conversatie niet gewenst is. b.v. "De sekstant is een meetinstrument" -> "Dit is een kindvriendlijke site. Pas op uw woorden!"

Eigen functies

In deze paragraaf gaan we eigen javasript functies maken. Meer uitleg vind je hier. Een functie is de manier om programmeercode te ordenen. Door gebruik te maken van functies kun je je code overzichtelijke maken. Je kunt stukken code vervangen door een functie om de grote lijn beter zictbaar te houden in je code.

Ben je al lekker bezig met het grafische deel dan kun je er voor kiezen om hier verder te gaan.

Een functie is een afgesloten geheel voorzien van een logische naam. In een programma wordt een functie zonder invoer en zonder uitvoer gedeclareerd door de volgende structuur:

 function naam_functie()   // declaratie naam
 {
   // hier komt de code die moet worden uitgevoerd
 }
voorbeeld

We gaan het een en ander duidelijk maken aan de hand van het voorbeeld in hoofdstuk Foutafhandeling. Bekijk nog eens dit voorbeeld en zie dat daar alle uitvoer velden leeg worden gemaakt in het stuk code

// maak alle uitvoer objecten leeg
         fout1object.innerHTML = "";
         fout2object.innerHTML = "";
         uitvoerobject.innerHTML = "";
Deze code gaan we vervangen door de functie maakLeeg(). Echter maakLeeg() is geen standaard functie. Die declareren we dus zo:
 function maakleeg()   // declaratie naam
 {
         document.getElementById('fout1').innerHTML = "";
         document.getElementById('fout2').innerHTML = "";
         document.getElementById('uitvoer').innerHTML = "";
 }
De start van de hele code wordt dan
    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />   
    <script type="text/javascript">
       /**
          functie maakLeeg zorgt ervoor dat de uitvoervelden gewist worden.
        */
       
      function maakLeeg()
      {
         document.getElementById('fout1').innerHTML = "";
         document.getElementById('fout2').innerHTML = "";
         document.getElementById('uitvoer').innerHTML = "";
      }
       
      function voeruit()  
      {                   
         //lees invoer
         let invoer1 = Number(document.getElementById('invoer1').value);
         let invoer2 = Number(document.getElementById('invoer2').value);

         //pak alle uitvoer objecten
         let fout1object = document.getElementById('fout1');
         let fout2object = document.getElementById('fout2');
         let uitvoerobject = document.getElementById('uitvoer');

         // maak alle uitvoer objecten leeg
         maakLeeg();

         // definieer een foutvlag
         .... etc

Eigen functies met argumenten

De introductie van maakLeeg() zet nog niet veel zoden aan de dijk. De hele functie voeruit() is nog steeds erg groot. Echter kijk eens naar dit stuk code die ook in het voorbeeld is te vinden.

         // test op foute invoer
         if( isNaN(invoer1) )
         {
          fout1object.innerHTML=document.getElementById('invoer1').value
                    + "is geen getal";
          foutje = true; // zet de foutvlag
         }
         else
         {
          if(invoer1==0)
          {
            fout1object.innerHTML="De invoer mag niet 0 zijn";
            foutje = true; // zet de foutvlag
          }
         }

Dit zelfde stuk wordt ook uitgevoerd voor invoer2. Het is dus zinvol om hier een functie in te zetten. Die functie moet het volgende kunnen. Een fout ontdekken in een invoerveld en een boodschap plaatsen in het juiste uitvoerveld. De functie moet na aanroep teruggegeven of er wel of niet een fout is opgetreden. We moeten dus een functie aanmaken die invoer nodig heeft en uitvoer genereerd. Een algemene syntax is:

 // declaratie naam functie en namen benodigde argumenten
 function naam_functie(inv1,inv2,inv3, ... )   
 {
   // hier komt de code die moet worden uitgevoerd
   return informatie; // geef de aanroepende code informatie uit het proces.  
 }

Nu toegepast op het voorbeeld

   /*
    functie isInvoerFout
    De functie heeft de volgende argumenten nodig:
     invoer: een variabele die mogelijk een getal bevat
     invoerid: een string die de id bevat van het invoer element in de htmlcode
     uitvoerid: een string die de id bevat van het invoer element in de htmlcode
    De functie geeft terug:
       true: als invoer geen getal is of gelijk is aan 0.
       false: als invoer wel een getal is en ongelijk is aan 0.
   */
   function isInvoerFout( invoer, invoerid , uitvoerid )
   {
     let fout=false; // Er is nog geen fout
     fout1object=document.getElementById(uitvoerid);
     if( isNaN(invoer) ) // test of de invoer een getal is
     { // geen getal. melding aan gebruiker, foutvlag wordt true
       fout1object.innerHTML=document.getElementById(invoerid).value
                    + "is geen getal";
       fout = true; 
     }
     else
     {
       if(invoer==0) // test of de invoer gelijk is aan 0.
       { // getal is gelijk aan 0. melding aan gebruiker, foutvlag wordt true
         fout1object.innerHTML="De invoer mag niet 0 zijn";
         fout = true; // zet de foutvlag
       }
     }
     return fout;
   }

De gehele code wordt nu

    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />   
    <style>
       table { border: ridge green 3pt;}
       td { border-bottom: solid green 1pt;}
    </style>

    <script type="text/javascript">
       /**
          functie maakLeeg zorgt ervoor dat de uitvoervelden gewist worden.
        */
       
      function maakLeeg()
      {
         document.getElementById('fout1').innerHTML = "";
         document.getElementById('fout2').innerHTML = "";
         document.getElementById('uitvoer').innerHTML = "";
      }
       
      function isInvoerFout( invoer, invoerid , uitvoerid )
      {
         let fout=false; // Er is nog geen fout
         fout1object=document.getElementById(uitvoerid);
         if( isNaN(invoer) )
         {
           fout1object.innerHTML=document.getElementById(invoerid).value
                        + "is geen getal";
           fout = true; // zet de foutvlag
         }
         else
         {
           if(invoer==0)
           {
             fout1object.innerHTML="De invoer mag niet 0 zijn";
             fout = true; // zet de foutvlag
           }
         }
         return fout;
      }

      function voeruit()  
      {                   
         //lees invoer
         let invoer1 = Number(document.getElementById('invoer1').value);
         let invoer2 = Number(document.getElementById('invoer2').value);

         // maak alle uitvoer objecten leeg
         maakLeeg();

         // definieer een foutvlag
         let foutje=false; // Een fout vlag. Voorlopig nog geen fout dus
                           // foutje maken we false

         // definieer uitkomst tekst nu nog leeg. Wordt alleen gevuld als
         // er geen fout optreedt                  
         let uitkomst="";
         
         // test op foute invoer nb: || is de logische vergelijking of.
         
         foutje = isInvoerFout(invoer1,'invoer1','fout1');
         foutje = isInvoerFout(invoer2,'invoer2','fout2') || foutje;
         
         // Nu alleen aan het werk als er geen fout is opgetreden
         // ofwel foutje is false
         // "!foutje" staat voor "niet foutje" 
         if( !foutje )
         {
          uitkomst = invoer1*invoer2 + invoer1/invoer2 + invoer2/invoer1;
          uitkomst = invoer1 +"×"+ invoer2 +" + " 
                     + invoer1 +"/"+ invoer2 + " + "
                     + invoer2 +"/"+ invoer1 + " = " + uitkomst;
          document.getElementById('uitvoer').innerHTML=uitkomst;
         }
      }                   
    </script>
  </head>
  <body>
  <form onsubmit="return false;">
  <table summary="">
    <tr>
      <td>
             Geef twee getallen
      </td>
    </tr>
    <tr>
      <td valign="top">
        <table summary="">
            <tr>
                <td><input id="invoer1" value="" /></td>
                <td id="fout1"><td>
            </tr>
            <tr>
                <td><input id="invoer2" value="" /></td>
                <td id="fout2"><td>
            </tr>
        </table>
      </td>
    </tr>
    <tr>
      <td  valign="top">
         <button onclick="javascript:voeruit();">Voer uit</button>
      </td>
    </tr>
    <tr>
      <td id="uitvoer" valign="bottom">
      </td>
    </tr>
  </table>
  </form>
  </body>
  </html>

Je ziet de code van voeruit() is nu aanzienlijk korter en daardoor beter te lezen. Bovendien hebben we een zelde stuk code één keer gemaakt, maar twee keer ingezet. Vuistregels voor het inzetten van functies zijn:

  • Moet ik dezelfde code nog vaker gebruiken
  • Is mijn functie zo lang dat ik hem beter kan opknippen. (Groter dan 1 A4 print)

Functies en flowcharts

De flowcharts die we hebben gezien in de vorige hoofdstukken zijn direct te gebruiken voor functies zonder argumenten, die niets teruggeven. Hiernaast vind je een flowchart voor een functie die de Body Mass Index berekent met als argumenten lengte en gewicht en die de berekende bmi teruggeeft. Het parallellogram in de flowchart naast start geeft aan dat er twee argumenten zijn. Het parallellogram naast eind geeft aan dat het bmi wordt teruggegeven. De code voor deze functie is:

/*
  functie bmi berekent de Body Mass Index
  lengte: lengte in meters
  gewicht: gewicht in kilogram
*/
function bmi(lengte,gewicht)
{
  let bmi=NaN;
  if(lengte > 0 )
  {
    if(lengte > 0 )
    {
      bmi=gewicht/(lengte*lengte);
    }		
  }
  return bmi;
}
Opdrachten
  1. Pas de code uit opgave 30 (hoofdstuk herhaling aan) zoals in bovenstaand voorbeeld is gedaan. Maak flowcharts voor ieder functie in de code.
  2. Maak een functie somVanRij(begin,eind,stap) die de som van de getallen beginnend bij "begin" en eindigend bij "eind" met tussenstappen "stap" uitrekent. Gebruik daarbij de code uit de vorige opgave en pas die code uit de vorige opgave daarna zo aan dat de berekening wordt gedaan door deze functie. Maak ook een flowchart voor deze functie.