Funktionsudtryk

dec 7, 2021

I JavaScript er en funktion ikke en “magisk sprogstruktur”, men en særlig form for værdi.

Den syntaks, som vi brugte før, kaldes en funktionsdeklaration:

function sayHi() { alert( "Hello" );}

Der findes en anden syntaks til at oprette en funktion, som kaldes et funktionsudtryk.

Den ser således ud:

let sayHi = function() { alert( "Hello" );};

Her oprettes funktionen og tildeles variablen eksplicit, ligesom enhver anden værdi. Uanset hvordan funktionen er defineret, er det bare en værdi, der er gemt i variablen sayHi.

Betydningen af disse kodeeksempler er den samme: “opret en funktion, og læg den i variablen sayHi“.

Vi kan endda udskrive denne værdi ved hjælp af alert:

function sayHi() { alert( "Hello" );}alert( sayHi ); // shows the function code

Bemærk venligst, at den sidste linje ikke kører funktionen, fordi der ikke er nogen parentes efter sayHi. Der findes programmeringssprog, hvor enhver omtale af et funktionsnavn medfører, at den udføres, men sådan er JavaScript ikke.

I JavaScript er en funktion en værdi, så vi kan behandle den som en værdi. Koden ovenfor viser dens strengrepræsentation, som er kildekoden.

Sikkert, en funktion er en speciel værdi, i den forstand at vi kan kalde den som sayHi().

Men det er stadig en værdi. Så vi kan arbejde med den som med andre slags værdier.

Vi kan kopiere en funktion til en anden variabel:

function sayHi() { // (1) create alert( "Hello" );}let func = sayHi; // (2) copyfunc(); // Hello // (3) run the copy (it works)!sayHi(); // Hello // this still works too (why wouldn't it)

Her er, hvad der sker ovenfor i detaljer:

  1. Funktionsdeklarationen (1) opretter funktionen og placerer den i variablen med navnet sayHi.
  2. Linje (2) kopierer den til variablen func. Bemærk igen: Der er ingen parenteser efter sayHi. Hvis der var det, ville func = sayHi() skrive resultatet af opkaldet sayHi() ind i func, ikke selve funktionen sayHi.
  3. Nu kan funktionen kaldes som både sayHi() og func().

Bemærk, at vi også kunne have brugt et funktionsudtryk til at deklarere sayHi, i den første linje:

let sayHi = function() { alert( "Hello" );};let func = sayHi;// ...

Alt ville fungere på samme måde.

Hvorfor er der et semikolon i slutningen?

Du undrer dig måske over, hvorfor har funktionsudtryk et semikolon ; til sidst, men ikke funktionsdeklaration:

function sayHi() { // ...}let sayHi = function() { // ...};

Svaret er enkelt:

  • Der er ikke behov for ; i slutningen af kodeblokke og syntaksstrukturer, der bruger dem som if { ... }, for { }, function f { } osv.
  • Et funktionsudtryk anvendes inde i udsagnet: let sayHi = ...;, som en værdi. Det er ikke en kodeblok, men snarere en tildeling. Semikolon ; anbefales i slutningen af udsagn, uanset hvilken værdi der er tale om. Så semikolonet her har ikke noget med selve funktionsudtrykket at gøre, det afslutter bare udsagnet.

Callback-funktioner

Lad os se på flere eksempler på at videregive funktioner som værdier og bruge funktionsudtryk.

Vi skriver en funktion ask(question, yes, no) med tre parametre:

question Spørgsmålets tekst yes Funktion, der skal køres, hvis svaret er “Ja” no Funktion, der skal køres, hvis svaret er “Nej”

Funktionen skal spørge question og, afhængigt af brugerens svar, kalde yes() eller no():

function ask(question, yes, no) { if (confirm(question)) yes() else no();}function showOk() { alert( "You agreed." );}function showCancel() { alert( "You canceled the execution." );}// usage: functions showOk, showCancel are passed as arguments to askask("Do you agree?", showOk, showCancel);

I praksis er sådanne funktioner ganske nyttige. Den store forskel mellem en ask i det virkelige liv og eksemplet ovenfor er, at funktioner i det virkelige liv anvender mere komplekse måder at interagere med brugeren på end en simpel confirm. I browseren tegner en sådan funktion normalt et pænt udseende spørgevindue. Men det er en anden historie.

Argumenterne showOk og showCancel i ask kaldes callback-funktioner eller blot callbacks.

Tanken er, at vi overdrager en funktion og forventer, at den “kaldes tilbage” senere, hvis det er nødvendigt. I vores tilfælde bliver showOk callback for “ja”-svar og showCancel for “nej”-svar.

Vi kan bruge funktionsudtryk til at skrive den samme funktion meget kortere:

function ask(question, yes, no) { if (confirm(question)) yes() else no();}ask( "Do you agree?", function() { alert("You agreed."); }, function() { alert("You canceled the execution."); });

Her er funktionerne deklareret lige inde i ask(...)-opkaldet. De har intet navn og kaldes derfor anonyme. Sådanne funktioner er ikke tilgængelige uden for ask (fordi de ikke er tildelt variabler), men det er netop det, vi ønsker her.

Sådan kode optræder meget naturligt i vores scripts, det er i JavaScript’s ånd.

En funktion er en værdi, der repræsenterer en “handling”

Regulære værdier som strenge eller tal repræsenterer dataene.

En funktion kan opfattes som en handling.

Vi kan videregive den mellem variabler og køre den, når vi vil.

Funktionsudtryk vs. funktionsdeklaration

Lad os formulere de vigtigste forskelle mellem funktionsdeklarationer og -udtryk.

Først syntaksen: hvordan man skelner mellem dem i koden.

  • Funktionsdeklaration: En funktion, der er deklareret som en separat erklæring, i hovedkodeflowet.

    // Function Declarationfunction sum(a, b) { return a + b;}

  • Funktionsudtryk: En funktion, der oprettes inde i et udtryk eller inde i en anden syntaks-konstruktion. Her oprettes funktionen på højre side af “tildelingsudtrykket” =:

    // Function Expressionlet sum = function(a, b) { return a + b;};

Den mere subtile forskel er, når en funktion oprettes af JavaScript-motoren.

Et funktionsudtryk oprettes, når udførelsen når frem til det og kan kun bruges fra det tidspunkt.

Når udførelsesflowet passerer til højre side af tildelingen let sum = function… – here we go, er funktionen oprettet og kan bruges (tildeles, kaldes osv. ) fra nu af.

Funktionsdeklarationer er anderledes.

En funktionsdeklaration kan kaldes tidligere, end den er defineret.

En global funktionsdeklaration er f.eks. synlig i hele scriptet, uanset hvor den befinder sig.

Det skyldes interne algoritmer. Når JavaScript forbereder sig på at køre scriptet, leder det først efter globale funktionsdeklarationer i det og opretter funktionerne. Vi kan betragte det som en “initialiseringsfase”.

Og efter at alle funktionsdeklarationer er behandlet, udføres koden. Så den har adgang til disse funktioner.

For eksempel fungerer dette:

sayHi("John"); // Hello, Johnfunction sayHi(name) { alert( `Hello, ${name}` );}

Funktionsdeklarationen sayHi oprettes, når JavaScript forbereder sig på at starte scriptet, og den er synlig overalt i det.

…Hvis det var et funktionsudtryk, ville det ikke fungere:

sayHi("John"); // error!let sayHi = function(name) { // (*) no magic any more alert( `Hello, ${name}` );};

Funktionsudtryk oprettes, når udførelsen når frem til dem. Det ville kun ske i linjen (*). For sent.

En anden speciel egenskab ved funktionsdeklarationer er deres blokområde.

I strict mode er en funktionsdeklaration, når den befinder sig inden for en kodeblok, synlig overalt inden for denne blok. Men ikke uden for den.

Lad os for eksempel forestille os, at vi skal deklarere en funktion welcome() afhængigt af variablen age, som vi får under kørselstiden. Og så har vi planer om at bruge den et stykke tid senere.

Hvis vi bruger funktionsdeklaration, vil det ikke fungere efter hensigten:

let age = prompt("What is your age?", 18);// conditionally declare a functionif (age < 18) { function welcome() { alert("Hello!"); }} else { function welcome() { alert("Greetings!"); }}// ...use it laterwelcome(); // Error: welcome is not defined

Det skyldes, at en funktionsdeklaration kun er synlig inden for den kodeblok, som den befinder sig i.

Her er et andet eksempel:

let age = 16; // take 16 as an exampleif (age < 18) { welcome(); // \ (runs) // | function welcome() { // | alert("Hello!"); // | Function Declaration is available } // | everywhere in the block where it's declared // | welcome(); // / (runs)} else { function welcome() { alert("Greetings!"); }}// Here we're out of curly braces,// so we can not see Function Declarations made inside of them.welcome(); // Error: welcome is not defined

Hvad kan vi gøre for at gøre welcome synlig uden for if?

Den korrekte fremgangsmåde ville være at bruge et funktionsudtryk og tildele welcome til den variabel, der er erklæret uden for if og har den rette synlighed.

Denne kode fungerer efter hensigten:

let age = prompt("What is your age?", 18);let welcome;if (age < 18) { welcome = function() { alert("Hello!"); };} else { welcome = function() { alert("Greetings!"); };}welcome(); // ok now

Og vi kunne forenkle det endnu mere ved at bruge en spørgsmålstegnoperator ?:

let age = prompt("What is your age?", 18);let welcome = (age < 18) ? function() { alert("Hello!"); } : function() { alert("Greetings!"); };welcome(); // ok now

Hvornår skal man vælge funktionsdeklaration frem for funktionsudtryk?

Som tommelfingerregel gælder det, at når vi skal deklarere en funktion, er syntaksen for funktionsdeklaration den første, vi skal overveje. Det giver mere frihed i forhold til, hvordan vi organiserer vores kode, fordi vi kan kalde sådanne funktioner, før de er deklareret.

Det er også bedre for læsbarheden, da det er lettere at slå function f(…) {…} op i koden end let f = function(…) {…};. Funktionsdeklarationer er mere “iøjnefaldende”.

…Men hvis en funktionsdeklaration af en eller anden grund ikke passer os, eller hvis vi har brug for en betinget deklaration (vi har lige set et eksempel), så bør man bruge funktionsudtryk.

Summary

  • Funktioner er værdier. De kan tildeles, kopieres eller deklareres et hvilket som helst sted i koden.
  • Hvis funktionen er deklareret som en separat erklæring i hovedkodeflowet, kaldes det en “Funktionsdeklaration”.
  • Hvis funktionen er oprettet som en del af et udtryk, kaldes det et “Funktionsudtryk”.
  • Funktionsdeklarationer behandles, før kodeblokken udføres. De er synlige overalt i blokken.
  • Funktionsudtryk oprettes, når udførelsesflowet når frem til dem.

I de fleste tilfælde, hvor vi skal deklarere en funktion, er en funktionsdeklaration at foretrække, fordi den er synlig før selve deklarationen. Det giver os mere fleksibilitet i kodeorganiseringen, og det er normalt mere læsbart.

Så vi bør kun bruge et funktionsudtryk, når en funktionsdeklaration ikke er egnet til opgaven. Det har vi set et par eksempler på i dette kapitel, og vi vil se flere i fremtiden.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.