Waarom je zonder variabelen en functies vastloopt

Je hebt een trainingsopdracht: een pagina met een menu-knop en een klein formulier. Je wilt dat het menu openklapt, dat een foutmelding verschijnt bij een leeg veld, en dat er een “Bedankt!”-melding komt na versturen. Je begint enthousiast met een paar regels JavaScript, maar al snel merk je hetzelfde probleem: je schrijft dezelfde regels meerdere keren, je raakt kwijt welke waarde “nu geldt”, en je click-code wordt één grote brei.

Dat is precies het moment waarop variabelen, functies en events belangrijk worden. Ze geven je structuur: variabelen bewaren “state” (toestand), functies maken gedrag herbruikbaar en leesbaar, en events bepalen wanneer code draait. Samen zorgen ze ervoor dat je interactie niet alleen “werkt”, maar ook onderhoudbaar blijft in een echte opdrachtcontext.

In deze les leg je een fundament dat je steeds opnieuw gebruikt: je leert hoe je data bijhoudt (variabelen), hoe je logica netjes verpakt (functies), en hoe je die logica koppelt aan acties van gebruikers (events) zonder je DOM en je “state” door elkaar te halen.

De bouwstenen: wat is een variabele, functie en event precies?

Een variabele is een naam die verwijst naar een waarde die je nodig hebt om je pagina te laten reageren. Dat kan een getal zijn (aantal items), tekst (een melding), of een boolean zoals true/false (menu open of dicht). In browser-JS gebruik je variabelen ook vaak om DOM-elementen vast te houden die je later opnieuw nodig hebt, zoals een knop of een formulier. Zo voorkom je dat je steeds opnieuw dezelfde elementen moet opzoeken en houd je je code leesbaar.

Een functie is een blok code met een naam, bedoeld om één duidelijke taak uit te voeren. In interactiecode is een functie vaak “de handler” (wat moet gebeuren bij een klik), of een helper zoals “update de UI op basis van de state”. Functies helpen je ook om het principe uit de vorige les vast te houden: input verwerken → beslissen → DOM bijwerken. Als je die stappen in functies scheidt, wordt je code voorspelbaar en makkelijker te debuggen.

Een event is het signaal dat er iets gebeurt in de browser: click, input, submit, load, enzovoort. Met een event listener koppel je een functie aan zo’n event. Dit past direct bij het idee uit de vorige les dat JavaScript meestal reactief is: het wacht tot er iets gebeurt, voert dan een beslissing uit, en werkt daarna de DOM bij (bij voorkeur via classes).

Hieronder zie je het verschil in rol, zodat je bij het lezen van code sneller herkent “waar je naar kijkt”:

Dimensie Variabelen Functies Events + listeners
Hoofdfunctie Waarden en referenties bewaren (state, DOM, tussenresultaten). Logica bundelen in herbruikbare stappen. Bepalen wanneer functies draaien (gebruikersactie of browsermoment).
Typisch in opdrachten isOpen, emailValue, menuEl, submitBtn. toggleMenu(), validateEmail(), renderMessage(). button.addEventListener("click", ...), form.addEventListener("submit", ...).
Veelgemaakte fout DOM als “database” gebruiken (bijv. tekst lezen om state te raden). Alles in één mega-functie stoppen met meerdere verantwoordelijkheden. Luisteren op het verkeerde element of default browsergedrag vergeten (bijv. submit reload).
Best practice Gebruik const voor wat niet herassigned wordt, let voor state die verandert. Houd functies klein en doelgericht: één taak, duidelijke naam. Handler kort houden: lees input → update state → update UI; voorkom “magische” selectors.

Variabelen: state vasthouden zonder de DOM als waarheid te misbruiken

In training-opdrachten voelt het verleidelijk om de DOM te gebruiken om te onthouden wat er aan de hand is: “Als de knoptekst ‘Sluiten’ is, dan zal het menu wel open zijn.” Dat werkt even, maar het breekt zodra iemand de tekst aanpast, de taal verandert, of een designer besluit dat de knop een icoon krijgt zonder tekst. Een robuustere aanpak is: state is data, UI is de weergave daarvan. Variabelen zijn jouw plek om die data vast te houden.

Gebruik in de praktijk twee soorten variabelen. Ten eerste: referenties naar elementen, zoals de menu-knop en het menu zelf. Die verander je meestal niet, dus je gebruikt daar vaak const voor. Ten tweede: toestandsvariabelen zoals isOpen of isValid. Die veranderen in de tijd, dus die maak je met let. Dit sluit aan bij het state-denken uit de vorige les: jij bepaalt de toestand, daarna update je de UI (bijv. class toggelen). Het wordt dan veel makkelijker om oorzaken en gevolgen te volgen: “Door deze click wordt isOpen true, dus krijgt het menu .is-open.”

Een belangrijke nuance: ook als je classes toggelt, betekent dat niet dat de class je “state” is. Die class is het effect in de UI. Je kunt hem wel gebruiken als afgeleide bron in simpele scripts, maar zodra de interactie groeit (bijv. menu kan ook dicht via Escape, of dichtklikken buiten het menu) wil je één duidelijke plek waar je state beheert. Dat vermindert bugs zoals “menu staat visueel open maar intern denkt je code dat het dicht is”.

Veelvoorkomende misvatting bij beginners is dat variabelen “alleen voor getallen” zijn. In browser-JS zijn variabelen juist een organiserend hulpmiddel: je bewaart er DOM-elementen, configuratie (bijv. teksten voor meldingen), en flags in. Als je merkt dat je dezelfde selector of dezelfde tekst drie keer typt, is dat vaak een signaal dat een variabele je code stabieler en leesbaarder maakt.

Functies: van rommelige handlers naar herbruikbare stappen

Zodra je twee interacties hebt, ontstaat de neiging om alles direct in addEventListener te schrijven. Dat gaat snel, maar je handler wordt een mengsel van: waarden lezen, voorwaarden checken, classes zetten, tekst vervangen, en misschien ook nog een melding tonen. Dat is precies de valkuil uit de vorige les: één stuk code krijgt te veel verantwoordelijkheden. Functies zijn hier je gereedschap om orde te scheppen.

Een sterke vuistregel is: één functie = één intentie. Bijvoorbeeld: validateEmail(value) doet alleen validatie en geeft een resultaat terug (bijv. true/false of een foutbericht). Een andere functie renderEmailState(isValid) doet alleen UI-updates (classes, foutmelding). En een handler-functie onEmailInput(event) verbindt die twee: leest input, berekent state, roept render aan. Hierdoor kun je later makkelijker iets aanpassen zonder onverwachte bijwerkingen. Wil je de tekst van de foutmelding veranderen? Dan zit dat in één render-functie, niet verspreid in drie handlers.

Functies maken ook debuggen makkelijker. Als je straks met console.log werkt, kun je in kleine functies sneller zien waar het misgaat: is de input leeg, is de state fout, of gaat het renderen verkeerd? Daarnaast helpt een naamgeving die de “flow” zichtbaar maakt. Namen als handleSubmit, toggleMenu, updateUI laten meteen zien wat er gebeurt. Namen als doStuff of test maken je code onscanbaar, vooral als je na een week terugkomt.

Een tweede misvatting: “Functies zijn alleen voor hergebruik.” Hergebruik is mooi, maar het grootste voordeel in beginnersopdrachten is vaak leesbaarheid en scheiding van taken. Zelfs als je een functie maar één keer aanroept, kan het nog steeds waardevol zijn omdat het de intentie labelt. Zie een functie als een mini-paragraaf in code: je geeft een stuk logica een titel, zodat de rest van je bestand te lezen blijft.

Events: het reactiemodel van de browser goed benutten

Events zijn de schakelaars die je gedrag “aanzetten”. In de vorige les zag je al: JavaScript draait niet continu door; het reageert vooral op gebeurtenissen. Daardoor is het belangrijk dat je helder hebt: wie triggert dit, wanneer, en wat is het standaardgedrag? Vooral bij formulieren maakt dat het verschil tussen “netjes gedrag” en “waarom herlaadt mijn pagina steeds?”

Een event listener koppel je idealiter aan een element met de juiste betekenis. Klik-gedrag hoort bij een <button>, versturen hoort bij een <form> met een submit listener. Dat is niet alleen “netter”; het maakt je gedrag ook voorspelbaar voor toetsenbordgebruik en toegankelijkheid. Als je click-handlers op willekeurige containers zet, krijg je sneller problemen met bubbelen (events die door de DOM omhoog gaan) en met onderhoud, omdat je selectors instabiel worden.

Het standaardgedrag van de browser is ook een belangrijk onderdeel van het eventmodel. Een submit doet standaard een navigatie/reload. Soms wil je dat, soms wil je eerst je eigen feedback tonen. Dan gebruik je in de handler vaak event.preventDefault() zodat je controle hebt over de flow. Dit is geen “hack”, maar een bewuste keuze: jij beslist of je het ingebouwde gedrag volgt of overschrijft voor betere UX in je opdracht.

Een praktisch best practice-patroon voor beginners is: laat je handlers zo klein mogelijk en laat ze vooral coördineren. De handler leest input uit het event (of uit het DOM), werkt state bij, en roept één of meerdere functies aan om de UI te updaten. Als je merkt dat je handler 30 regels lang wordt, is dat bijna altijd een signaal dat je render/validatie/toggle-logica beter in eigen functies kunt zetten.

[[flowchart-placeholder]]

Voorbeeld 1: Een menu-knop die state beheert en classes toggelt

Stel: je hebt een mobiel menu dat standaard verborgen is met CSS, en zichtbaar wordt met een class .is-open. De HTML bevat het menu al (progressive enhancement), dus zonder JS zijn de links er nog steeds. Je JavaScript hoeft dan maar één ding te doen: bij een klik de state omzetten en de UI bijwerken.

De stap-voor-stap aanpak in termen van deze les ziet er zo uit. Je maakt const variabelen voor de elementen (knop en menu), zodat je niet overal selectors herhaalt. Je maakt let isOpen = false als state. Daarna koppel je een click-listener aan de knop, en in de handler flip je de state: isOpen = !isOpen. Vervolgens update je de UI: je zet de class op het menu op basis van isOpen, en je past eventueel de knoptekst aan (“Menu” ↔ “Sluiten”). Daarmee houd je de verantwoordelijkheid scherp: de variabele zegt “wat is waar”, de DOM laat het zien.

Impact in een trainings- of organisatiecontext: dit soort menu komt vaak terug op meerdere pagina’s. Als je deze structuur aanhoudt, kun je dezelfde aanpak herhalen zonder copy-paste chaos. Het voordeel is voorspelbaar gedrag en makkelijke aanpassingen door designers (zij veranderen CSS achter .is-open, jij hoeft geen JS-styles te injecteren). Beperking: als je state en UI door elkaar haalt (bijv. state afleiden uit knoptekst), krijg je snel inconsistenties wanneer de UI verandert zonder dat je code het verwacht.

Voorbeeld 2: Live validatie + submit-afhandeling zonder pagina refresh

Neem een formulier met een e-mailveld en een “Verstuur”-knop. HTML kan al basisvalidatie doen met required en type="email", maar je wilt eigen feedback: een foutmelding onder het veld, een rode rand via .has-error, en een knop die uit staat zolang het veld niet goed is. Hier zie je perfect hoe variabelen, functies en events samenwerken.

Je start met variabelen: const formEl, const emailEl, const submitBtn, const errorEl (of een container waar je de fouttekst in zet). Je gebruikt let isEmailValid = false als state. Dan maak je functies met één taak: validateEmail(value) bepaalt of het voldoet aan jouw regels en geeft een helder resultaat terug (bijv. boolean of message). renderEmailFeedback(isValid, message) past de UI aan: .has-error aan/uit, fouttekst invullen/legen, en submitBtn.disabled = !isValid. Vervolgens koppel je events: een input listener op emailEl die bij elke wijziging valideert en rendert, en een submit listener op formEl die checkt of je door mag gaan of dat je preventDefault() doet en feedback toont.

De voordelen zijn concreet: gebruikers krijgen meteen feedback, maken minder fouten, en het formulier voelt “levend” zonder dat je een complete app bouwt. De beperking blijft belangrijk (zeker in echte workflows): JS-validatie is gebruikersgemak, geen beveiliging. In productie moet validatie ook server-side gebeuren, omdat je JS kunt omzeilen. In training-opdrachten is de winst vooral dat je leert denken in state en UI-update, en dat je standaard browsergedrag bewust leert sturen in plaats van erdoor verrast te worden.

De kern in één mental model

Als je interactie bouwt, kun je bijna altijd dit patroon volgen:

  • Variabelen houden je state en je element-referenties vast (zodat je niet hoeft te gokken via UI-tekst).

  • Functies splitsen de logica op in leesbare stukken: valideren, togglen, renderen.

  • Events bepalen wanneer het gebeurt: klik, input, submit, en soms met het standaardgedrag bewust aan of uit.

Dit maakt je code niet alleen werkend, maar ook “teamproof”: anderen kunnen het scannen, aanpassen, en uitbreiden zonder dat alles breekt. This sets you up perfectly for DOM-basis & debugging met console [15 minutes].

Last modified: Tuesday, 10 March 2026, 3:33 PM