Hvad er en funktion
En funktion er en "beholder" til en blok af kode. Funktioner hjælper os med:
- At undgå repetition. En enkelt funktion kan afvikles mange gange.
- At skabe lokale scopes som indkapsler kode, hvilket kan begrænse og beskytte adgangen til vores data
- At opdele koden i komponenter og dermed gøre vores kodebase mere overskuelig, modular og skalérbar
First Class Functions
Funktioner i JavaScript er First Class Functions. Dvs. at de bliver behandlet som værdier. En funktion kan, som alle andre værdier, blive gemt i en variabel, indgå i et array, en objekt property eller blive sendt som argument til en anden funktion.
En funktion som returnerer, eller modtager en funktion, kaldes en higher-order funktionIndbyggede funktioner
JavaScript (og de fleste andre programmeringssprog) har indbygget funktionalitet, f.eks. funktioner til matematiske udregninger. Når JavaScript afvikles i en browser har vi også adgang til en række Web API funktioner, specielt designet til web funktionalitet.
Indbyggede funktioner skal ikke deklareres (de er allerede deklareret i APIet)
alert() er en funktion der er indbygget i window objektet. Vi kunne også have skrevet window.alert('Hello');
Når funktioner er indkapslet i objecter kaldes de ofte metoder.
Function statements
Som regel vil vi gerne gøre mere end bare at afvikle indbyggede funktioner. Heldigvis kan vi deklarere vores egne funktioner. Den mest alindelige måde at gøre dette er med et function statement som indeholder:
- Et function keyword
- Et navn på funktionen
- Et sæt paranteser til eventuelle parametre
- En function body - et sæt curly brackets som udgør funktionens scope og indeholder alle funktionens lokale data
Parametre/ argumenter
Argumenter er data som passes til funktionen når den bliver kaldt. Disse data er kun tilgængelige inde i funktionens body (Read: Scope)
Før vi kan aflevere argumenter til funktionen må vi opstille parametre i funktions-deklarationen. Tænk på parametere som tomme placeholders til data
Hvis vi bruger flere argumenter/parametre, sepererer vi dem med kommaer.
Bemærk at parametre og argumenter er to sider af samme sag. Men vi bruger de forskellige termer afhængig af context. Termen parameter bruges i funktions-deklarationen, og termen argument når funktionen kaldes.
Scope
Scope er det "miljø" vi har adgang til i en given context. Vi kan deklarere en variabel eller en funktion i det globale scope, eller inde i et lokalt scope i en funktion. I JavaScript har alle funktioner adgang til evt. "forældre scopes" hele vejen op til det global scope, men kun funktionen selv og dens evt. child funktioner har adgang til sit eget lokale scope
Returværdier
Indtil videre har alle vores funktions-eksempler afviklet kode men det er ofte mere brugbart, i stedet, at lade funktioner returnere en værdi
Lad os lave et program der kan lægge to tal sammen:
Returværdier gør det nemt at aflevere data som argumenter fra en funktion til en anden:
Higher-order Functions
Husk at JavaScript understøtter higher-order funktioner. Det betyder at vi kan vælge at aflevere selve funktionen, i stedet for "bare" dens returværdi. Vi gør dette ved at udelade parenteserne når vi afleverer den. Vi kan nu, i stedet, afvikle funktionen inde i modtager-funktionens scope ved at tilføje paranteser her.
En hver funktion som modtager, eller returnerer, andre funktioner (i stedet for værdier) er Higher-order funktioner
Hoisting
JavaScript bliver fortolket med et princip kaldet hoisting. Hoisting betyder at funktioner (deklareret med et function statement) vil blive opbevaret i hukommelsen inden koden afvikles. Derfor er det muligt at kalde en funktion før den er blevet deklareret.
Hoisting er ikke almindeligt. I de fleste programmeringssprog må man deklarere en funktion før den kan kaldes.
Anonyme funktioner og function expressions
En funktion behøver ikke nødvendigvis at blive deklareret med et navn. Termen for en navnløs funktion er en anonymous function. Det er meget almindeligt at deklarere en variabel og sætte dens værdi til en anonym funktion.
Denne praktis kaldes en function expression og virker stortset på samme måde som et function statement, men med den betydelige forskel at function expressions ikke bliver hoisted. Function expressions skal deklareres før de kan kaldes
IIFE
IIFE, eller Immediately Invoked Function Expression, er en anden typisk brug for anonyme funktioner. En IIFE bliver afviklet umidelbart efter den er deklareret.
IIFE bruges typisk initialisering af a program. F.eks. når vi har brug for at indkapsle et stykke kode der kun skal køres én gang.
Indlejrede funktioner og closures
Et af de mere langhårede koncepter i JS er closures.
Closures er når en indre (indlejret) funktion returneres fra en ydre (forældre) funktion og kaldes efter den ydre funktion er afviklet, død og begravet. Pga. closure konceptet, har den returnerede indre funktion stadig adgang til de variabler der blev deklareret i den ydre (døde og begravede) funktions scope.
Det interesante her er forskellen mellem a og b.
b bliver deklareret igen hver gang vi kalder c() og værdien resettes derfor hele tiden, i modsætning til a (som eksisterer som et closure) og derfor aldrig bliver gen-deklareret. Derfor ændres værdien hver gang c() bliver afviklet.
Arrow function syntax (kun ECMAScript 6+)
Function expressions kan nu deklareres med en kortere syntax.
Vi fjerner function keywordet og udskifter det med en "pil" =>
efter paranteserne
Vi kan endda forkorte koden yderligere ved at udelade en function body og i stedet benytte arrow funktionens implicitte returværdi
Callback functions
Som nævnt kan vi aflevere en funktion som et parameter til en anden (higher-order) funktion. Dette er meget almindeligt med såkaldte callback funktioner.
Et callback er når funktion B er afleveret som parameter til funktion A og afviklet ummidelbart efter Funktion A er afviklet.
addEventListener funktionen, modtager (i dette tilfælde) 2 parametre. Det første parameter er typen af event (I dette tilfælde click). Det andet parameter er en anonym funktion, afviklet som callback når eventen detektes
Handler funktioner
I eksemplet overfor, brugte vi en anonym callback funktion. Nogen gange er det mere hensigtsmæssigt at aflevere en ekstern callback funktion, især hvis vi ønker at afvikle samme fuktionalitet på flere "eventlyttere". Eksterne callback funktioner kaldes ofte handler funktioner fordi de 'håndterer' hvad der skal ske når eventen forekommer.
This og event.target
Event handlere i loops
Du har måske bemærket brugen af this i de foregående eksempler.
Når this keywordet bruges i en event handler, peger det på det objekt eventen er knyttet til i den givne context.
Handler funktionene vil altså fortolke this som det element, der er blevet klikket på, og triggede funktionen.
Event delegation)
This keywordet er derfor meget nyttigt hvis vi skal sætte events på et ukendt antal elementer i et loop. F.eks. alle elementer med en bestemt klasse, som i eksemplet herunder:
Hvis du klikker på HTML fanen på denne fiddle, kan du se at alle valgte elementer har en data attribut. Vi har adgang til hvert elements individuelle attributter (og øvrige properties) v.h.a. this.
Bemærk at handler funktionen kan tage event objektet som argument.
Det betyder at vi faktisk kan delegere én enkelt eventlistener til alle child-elementer. For at ramme disse, bruges event.target i stedet for this.
Objekt Orienteret JS
Object Orientet Programming (OOP) udgøres af specielle typer blueprint funktioner (ofte kaldet klasser). Koden inde i selve klassen er en definition og bliver ikke afviklet direkte. I stedet opretter vi instanser (objekter), der virker som kloner af klassen og arver alle klassens propperties (variabler) og metoder (funktioner).
OOP tillader os at minimalisere gentagelser og indkapsle og beskytte data. Et andet vigtigt koncept i OOP er inheritance. Ikke bare vores instanseser af klassen kan arve propperties/ methods. Vi kan faktisk lave sub classes som arver alting fra en super class.
Indtil ES6, har JavaScript ikke haft et class keyword, som traditionelle OOP languages. Så hidtil har vi bare oprettet instanser af en såkaldt constructor funktion v.h.a et new keyword.
Constructor function
Vi har nu skabt to instancer af "Animal".
Bemærk at navnet på constructer funktionen er deklareret med PascalCase (Stort for-bogstav i hvert ord). Dette er en konvention for klasse definitioner i OOP.
Ny ES6 class syntax
Som nævnt har JavaScript nu "rigtige"' class keywords.
Dette er gode nyheder for programmører der er vant til "traditionelle" programmeringssprog (f.eks. JAVA og C++), fordi syntaksen nu er den samme. Som i disse sprog, kan vi deklarere statiske metoder (methods som tilhører selve klassen, ikke bare instanserne), vi kan dog ikke deklarere private metoder eller properties i JS.
Bemærk at for at beregne personens alder refererer vi til Person.currentYear(). Vi bruger ikke this.currentYear() fordi metoden er statisk.
Bemærk også at klasser, i modsætning til den foregående constructer function, ikke bliver hoisted. En klasse skal altså deklareres før vi kan skabe instanser.
Inheritance in OOP
Vi kan definere sup classes som arver alle properties/methods fra en super class
Lad os prøve at extende vores Person klasse til to sub klasser: Employee og Customer
Begge typer er "personer" så de bør arve de gennerelle properties fra Person klassen. Dette gør vi med et super keyword.
Begge typer kan nu, udover Person propperties, have deres egne individuelle properties:
Object Literals og Prototypes
Det er vigtigt at notere sig at der er andre modeller for at skabe OOP funktionalitet i JS.
En af disse modeller er at lave object literals og benytte Object.setPrototypeOf til at skabe nye objekter som arver properties/methods.
Her er et eksempel der viser denne tilgang.