Skip to content

Functional Programming

marcoFijan edited this page Nov 9, 2020 · 1 revision

Wat is Functional Programming?

In dit vak gaan we aan de slag met functional programming. Maar wat is functional programming nu precies? Dat leg ik hier kort voor mezelf vast.

Focus op resultaten en functies

Met functional programming zorg je ervoor dat zoveel mogelijk, het liefst alle, functies iets returnen. Alle functies zijn als het ware 'getters' die iets teruggeven wanneer deze worden aangeroepen. Er wordt dus meer gefocust op de functies. Je maakt meerdere kleine functies zodat je deze kunt terugroepen. Functies kun je in javascript opslaan in variablen. Als je meerdere keren een specifiek datastuk nodig hebt, is het mogelijk om simpelweg de variable met die functie aan te roepen in plaats van elke keer weer die if/else-statement of for-loop te moeten schrijven.

Variablen delen is out of the question

Bij functional programming zorg je ervoor dat alle variablen binnen zijn eigen scope worden gebruikt, gewijzigd en aangemaakt. Als je data nodig hebt van een andere scope, zoals de global scope, geef je deze mee met een parameter. Op deze manier kun je die data binnenhalen en bewerken. Ook blijft de oorspronkelijke data in tact en worden deze niet overridden.

Functional patterns

Er zijn meerdere functional patterns binnen functional programming. Zo'n functional pattern stel je van te voren vast. Een pattern is een set van standaarden en best practices om je code consistent te houden. Door met patterns te werken leer je om beter en mooier code te schrijven. Hier leg ik kort de verschillende patterns uit.

Higher order functions

Filter

Filter is een methode die zelf, zonder een for-loop of while, door een array heen gaat en deze filtered. De filter maakt dan gebruik van zijn eigen functie, 'callback', om een nieuwe array terug te geven die gefiltered is met de parameter die je hebt meegegeven.

Zonder filter

function filterThisArray(arr){
  let filteredArray = []
  for (let c = 0; c < arr.length; c++) {
    if(arr[c] != "a")
      filteredArray.push(arr[i])
  }
  return filteredArray
}

Met filter

function filterThisArray(arr){
  return arr.filter(item => item != "a")
}

Map

Een andere higher-order function is map. Map werkt een beetje het zelfde als forEach(), alleen geeft Map net als filter een array terug. Map gebruik je dus alleen als je echt een array terug wil hebben en die weer wilt gebruiken. Als je alleen maar een query hoeft uit te voeren over een bestaande array, kun je beter forEach() gebruiken.

Zonder map

function forEachArrayItem(arr){
  let remappedArray = []
  for (let c = 0; c < arr.length; c++){
    remappedArray[c].replace('a', 'b')
  }
  return remappedArray
}

Met map

function forEachArrayItem(arr){
  return arr.map(items => items.replace('a', 'b'))
}

Pure functions

Met pure functions zorg je ervoor dat je variablen alleen binnen de scope van de functie aanpast. Je kunt dan geen globale variable, buiten de function scope, aanpassen. Je geeft deze dan eerst mee met een parameter.

Impure

De impure versie is de sloderige versie. Hier pas je een variable aan buiten de scope van de functie

let aNumber = 1

function changeNumber() {
  return aNumber++
}
changeNumber()

Pure

Een netterie, pure, manier is schoner aangezien de oorspronkelijke data onaangetast blijft.

let aNumber = 1

function changeNumber(number) {
  return number++
}
changeNumber(aNumber)

Immutability

Immutability lijkt heel erg op pure functions. Alleen bij immutability gaat het om de data en niet om de functions. Bij immutability zorg je ervoor dat je de data, als in variablen en array's, niet direct aanpast. Deze laad je in via een parameter en vervolgens geef je een nieuwe variable, aangepast in de functie, weer terug.

Composition

Bij composition hak je de functies in kleine functions die 1 simpel dingetje doen. Deze functies kun je dan chainen om je antwoord te krijgen. Door je functies in kleine delen op te splitsen, is veel van je code herbruikbaar.

function getAnswerOfQuery(list, query){
  let results = list.map(answer => answer[query])                               // Create new array of the specific column called results
  let removedEmptyItems = removeEmptyItems(results)                             // Check if there are empty items in the array
  let hashResultsChecked = checkHash(removedEmptyItems)                         // Check if string begins with #
  let dataCleaned = checkHexCode(hashResultsChecked)                            // Check if string is a HEX
  return dataCleaned                                                            // Return the cleaned data
}

Gerichte naamgeving

Door een standaard te zetten voor de naamgeving van de functies, is je code leesbaarder wanneer je gebruik gemaakt van de andere functional patterns. Zo kun je de standaard zetten zoals: Voor elke functie waar ik data op haal, begin ik mijn functie met het woord 'get'. Op die manier weet je wanneer je een functie aanroept die begint met 'get', dat deze data ophaald uit of van iets.

Declaration

Voor goede, leesbare en bruikbare code is het het beste om je vaste variables van de global scope zo veel mogelijk bovenaan te definiëren. In de meeste gevallen, aangezien dit vaste variables zijn, geef je ook de declaratie const mee aan deze variablen

Gebruikte functional patterns

In mijn code maak ik gebruik van verschillende functional patterns. Hieronder geef ik per functional pattern één of meerdere voorbeelden vanuit mijn code.

High Order Functions

Map

Filter

Pure functions & Immutability

Composition

Declaration

Gebruikte bronnen