Functies als waarden

In JavaScript zijn functies gewoon waarden — net als getallen, strings en arrays. Je kunt ze opslaan in een variabele, meegeven als argument en teruggeven vanuit een functie.

// Functie opslaan in een variabele:
const begroet = function(naam) {
  return `Hallo ${naam}!`;
};

// Functie opslaan als property van een object:
const acties = {
  optellen: (a, b) => a + b,
  aftrekken: (a, b) => a - b
};

console.log(acties.optellen(3, 4));  // 7
console.log(acties.aftrekken(10, 3)); // 7
Dit principe — functies als "first-class citizens" — is de basis van callbacks, closures en hogere orde functies.

Callbacks

Een callback is een functie die je meegeeft als argument aan een andere functie. Die andere functie roept jouw callback aan op het juiste moment.

function voerUit(functie) {
  console.log('Voor de callback');
  functie(); // roep de meegegeven functie aan
  console.log('Na de callback');
}

function zegHallo() {
  console.log('Hallo!');
}

voerUit(zegHallo);
// "Voor de callback"
// "Hallo!"
// "Na de callback"

Callback met argument

function verwerkNamen(namen, callback) {
  for (const naam of namen) {
    callback(naam);
  }
}

verwerkNamen(['Anna', 'Bob', 'Carol'], (naam) => {
  console.log(`Hallo ${naam}!`);
});
// "Hallo Anna!"
// "Hallo Bob!"
// "Hallo Carol!"

Callbacks ken je al

// setTimeout — callback na vertraging
setTimeout(() => {
  console.log('1 seconde later');
}, 1000);

// addEventListener — callback bij event
knop.addEventListener('click', () => {
  console.log('geklikt!');
});

// Array methods — callback voor elk element
[1, 2, 3].forEach(n => console.log(n));
[1, 2, 3].filter(n => n > 1);
Je gebruikt callbacks de hele tijd — bij events, timers en array methods. Nu weet je hoe dat mechanisme heet.

Hogere orde functies

Een hogere orde functie is een functie die een andere functie accepteert als argument of teruggeeft als resultaat.

Functie accepteren

function pasToeTweeKeer(functie, waarde) {
  return functie(functie(waarde));
}

const verdubbel = n => n * 2;
console.log(pasToeTweeKeer(verdubbel, 3)); // 12 (3 → 6 → 12)

Functie teruggeven

function maakVermenigvuldiger(factor) {
  return function(getal) {
    return getal * factor;
  };
}

const verdubbel = maakVermenigvuldiger(2);
const verdriedubbel = maakVermenigvuldiger(3);

console.log(verdubbel(5));    // 10
console.log(verdriedubbel(5)); // 15

Eigen hogere orde functie

function filteredLog(array, filterFn) {
  array
    .filter(filterFn)
    .forEach(item => console.log(item));
}

const getallen = [1, 2, 3, 4, 5, 6];

filteredLog(getallen, n => n % 2 === 0); // 2, 4, 6
filteredLog(getallen, n => n > 3);       // 4, 5, 6

Closures

Een closure is een functie die toegang heeft tot variabelen van de buitenliggende scope, ook nadat die buitenliggende functie al is uitgevoerd.

function maakTeller() {
  let teller = 0; // lokale variabele

  return function() {
    teller++;
    return teller;
  };
}

const tel = maakTeller();
console.log(tel()); // 1
console.log(tel()); // 2
console.log(tel()); // 3

// Aparte teller — eigen closure:
const tel2 = maakTeller();
console.log(tel2()); // 1 (begint opnieuw)
Uitleg:
  • maakTeller() wordt uitgevoerd en is klaar
  • Toch onthoudt de teruggegeven functie de variabele teller
  • Elke aanroep van tel() werkt op dezelfde teller
  • tel2 heeft zijn eigen teller — onafhankelijk

Closure met configuratie

function maakGreeter(groet) {
  return function(naam) {
    return `${groet} ${naam}!`;
  };
}

const hallo = maakGreeter('Hallo');
const goedemorgen = maakGreeter('Goedemorgen');

console.log(hallo('Jan'));        // "Hallo Jan!"
console.log(goedemorgen('Lisa')); // "Goedemorgen Lisa!"

Closure voor private staat

function maakBankRekening(beginSaldo) {
  let saldo = beginSaldo; // privé — van buiten niet bereikbaar

  return {
    stortIn(bedrag) {
      saldo += bedrag;
      return saldo;
    },
    neemOp(bedrag) {
      if (bedrag > saldo) return 'Onvoldoende saldo';
      saldo -= bedrag;
      return saldo;
    },
    getSaldo() {
      return saldo;
    }
  };
}

const rekening = maakBankRekening(100);
rekening.stortIn(50);
console.log(rekening.getSaldo()); // 150
console.log(rekening.saldo);      // undefined — privé!
Closures worden veel gebruikt voor private staat, configureerbare functies en het bewaren van context.

Praktijkvoorbeelden

Debounce — niet te vaak uitvoeren

function debounce(functie, vertraging) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => functie(...args), vertraging);
  };
}

// Zoekfunctie pas uitvoeren als gebruiker stopt met typen:
const zoek = debounce((zoekterm) => {
  console.log(`Zoeken naar: ${zoekterm}`);
}, 300);

zoekVeld.addEventListener('input', (e) => zoek(e.target.value));

Once — slechts één keer uitvoeren

function eenmalig(functie) {
  let uitgevoerd = false;
  return function(...args) {
    if (!uitgevoerd) {
      uitgevoerd = true;
      return functie(...args);
    }
  };
}

const initialiseer = eenmalig(() => {
  console.log('App geïnitialiseerd!');
});

initialiseer(); // "App geïnitialiseerd!"
initialiseer(); // niets (al uitgevoerd)

Memoize — resultaten onthouden

function memoize(functie) {
  const cache = {};
  return function(arg) {
    if (cache[arg] !== undefined) {
      console.log('Uit cache!');
      return cache[arg];
    }
    const resultaat = functie(arg);
    cache[arg] = resultaat;
    return resultaat;
  };
}

const bereken = memoize((n) => {
  console.log(`Berekening voor ${n}`);
  return n * n;
});

bereken(5); // "Berekening voor 5" → 25
bereken(5); // "Uit cache!" → 25 (geen herberekening)
bereken(6); // "Berekening voor 6" → 36

Samenvatting

Concept Beschrijving
Functie als waarde Functies zijn waarden die je kunt opslaan en doorgeven
Callback Functie die als argument wordt meegegeven
Hogere orde functie Functie die een functie accepteert of teruggeeft
Closure Functie die variabelen van buitenliggende scope onthoudt