Funkční výrazy

Pro 7, 2021

V JavaScriptu není funkce „magickou strukturou jazyka“, ale speciálním druhem hodnoty.

Syntaxe, kterou jsme použili dříve, se nazývá deklarace funkce:

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

Existuje ještě jiná syntaxe pro vytvoření funkce, která se nazývá funkční výraz.

Vypadá takto:

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

Tady je funkce vytvořena a přiřazena proměnné explicitně, jako každá jiná hodnota. Nezáleží na tom, jak je funkce definována, je to prostě hodnota uložená v proměnné sayHi.

Smysl těchto ukázek kódu je stejný: „vytvoř funkci a vlož ji do proměnné sayHi„.

Tuto hodnotu můžeme dokonce vypsat pomocí alert:

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

Všimněte si, že poslední řádek funkci nespouští, protože za sayHi nejsou závorky. Existují programovací jazyky, kde jakákoli zmínka o názvu funkce způsobí její spuštění, ale JavaScript takový není.

V JavaScriptu je funkce hodnotou, takže s ní můžeme pracovat jako s hodnotou. Výše uvedený kód ukazuje její řetězcovou reprezentaci, což je zdrojový kód.

Jistě, funkce je zvláštní hodnota v tom smyslu, že ji můžeme volat jako sayHi().

Ale stále je to hodnota. Můžeme s ní tedy pracovat jako s jinými druhy hodnot.

Můžeme funkci zkopírovat do jiné proměnné:

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)

Tady je podrobně popsáno, co se děje výše:

  1. Deklarace funkce (1) vytvoří funkci a vloží ji do proměnné s názvem sayHi.
  2. Řádek (2) ji zkopíruje do proměnné func. Znovu si všimněte: za sayHi nejsou žádné závorky. Kdyby tam byly, pak by func = sayHi() zapsal do func výsledek volání sayHi(), nikoliv samotnou funkci sayHi.
  3. Nyní lze funkci volat jako sayHi() i func().

Všimněte si, že jsme mohli k deklaraci sayHi použít také funkční výraz, a to hned v prvním řádku:

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

Vše by fungovalo stejně.

Proč je na konci středník?

Mohlo by vás zajímat, proč má funkční výraz na konci středník ;, ale deklarace funkce ne:

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

Odpověď je jednoduchá:

  • Není třeba ; na konci bloků kódu a syntaktických struktur, které je používají, jako if { ... }, for { }, function f { } atd.
  • Funkční výraz se používá uvnitř příkazu: let sayHi = ...;, jako hodnota. Nejedná se o blok kódu, ale spíše o přiřazení. Na konci příkazů se doporučuje středník ;, ať už je hodnota jakákoli. Středník zde tedy nesouvisí se samotným funkčním výrazem, pouze ukončuje příkaz.

Zpětné funkce

Podívejme se na další příklady předávání funkcí jako hodnot a používání funkčních výrazů.

Napíšeme funkci ask(question, yes, no) se třemi parametry:

questionText otázkyyesFunkce, která se spustí, pokud je odpověď „Ano“noFunkce, která se spustí, pokud je odpověď „Ne“

Funkce by se měla zeptat na question a v závislosti na odpovědi uživatele zavolat yes() nebo 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);

V praxi jsou takové funkce docela užitečné. Hlavní rozdíl mezi skutečným ask a výše uvedeným příkladem spočívá v tom, že skutečné funkce používají složitější způsoby interakce s uživatelem než jednoduchý confirm. V prohlížeči taková funkce obvykle vykreslí pěkně vypadající okno s otázkou. Ale to už je jiný příběh.

Argumenty showOk a showCancel funkce ask se nazývají zpětné volání funkce nebo jen zpětné volání

Jde o to, že předáme funkci a očekáváme, že bude v případě potřeby později „zavolána zpět“. V našem případě se showOk stane zpětným voláním pro odpověď „ano“ a showCancel pro odpověď „ne“.

Pro zápis stejné funkce můžeme použít funkční výrazy mnohem kratší:

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."); });

Zde jsou funkce deklarovány přímo uvnitř volání ask(...). Nemají žádné jméno, a proto se nazývají anonymní. Takové funkce nejsou přístupné mimo ask (protože nejsou přiřazeny proměnným), ale právě to zde chceme.

Takový kód se v našich skriptech objevuje zcela přirozeně, je to v duchu JavaScriptu.

Funkce je hodnota představující „akci“

Obvyklé hodnoty jako řetězce nebo čísla představují data.

Funkci můžeme vnímat jako akci.

Můžeme ji předávat mezi proměnnými a spouštět, kdy chceme.

Výraz funkce vs. deklarace funkce

Zformulujme si klíčové rozdíly mezi deklarací a výrazem funkce.

Nejprve syntaxe: jak je v kódu rozlišit.

  • Deklarace funkce: funkce, deklarovaná jako samostatný příkaz v hlavním toku kódu.

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

  • Vyjádření funkce: funkce, vytvořená uvnitř výrazu nebo uvnitř jiné syntaktické konstrukce. Zde je funkce vytvořena na pravé straně „přiřazovacího výrazu“ =:

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

Drobnější rozdíl je v tom, kdy je funkce vytvořena JavaScriptovým enginem:

Funkční výraz je vytvořen v okamžiku, kdy k němu dojde při provádění a je použitelný až od tohoto okamžiku.

Jakmile tok vykonávání přejde na pravou stranu přiřazení let sum = function… – tady už to jde, funkce je vytvořena a od této chvíle ji lze používat (přiřazovat, volat atd. ).

Deklarace funkce se liší.

Deklaraci funkce lze zavolat dříve, než je definována.

Například globální deklarace funkce je viditelná v celém skriptu bez ohledu na to, kde se nachází.

To je dáno vnitřními algoritmy. Když se JavaScript připravuje na spuštění skriptu, nejprve v něm hledá globální Deklarace funkcí a vytváří funkce. Můžeme si to představit jako „inicializační fázi“.

A po zpracování všech Deklarací funkcí se kód spustí. Má tedy k těmto funkcím přístup.

Příklad to funguje takto:

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

Deklarace funkcí sayHi se vytvoří, když se JavaScript připravuje na spuštění skriptu, a je v něm všude vidět.

…Kdyby to byl funkční výraz, pak by to nefungovalo:

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

Funkční výrazy se vytvářejí, když k nim dojde při provádění. To by se stalo pouze v řádku (*). Příliš pozdě.

Další zvláštností deklarací funkcí je jejich blokový rozsah.

V přísném režimu, když je deklarace funkce uvnitř bloku kódu, je viditelná všude uvnitř tohoto bloku. Ne však mimo něj.

Představme si například, že potřebujeme deklarovat funkci welcome() v závislosti na proměnné age, kterou získáme během běhu. A pak ji plánujeme použít někdy později.

Pokud použijeme deklaraci funkce, nebude fungovat tak, jak má:

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

To proto, že deklarace funkce je viditelná pouze uvnitř bloku kódu, ve kterém se nachází.

Tady je další příklad:

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

Co můžeme udělat, aby welcome byla viditelná mimo if?

Správný postup by byl použít funkční výraz a přiřadit welcome proměnné, která je deklarovaná mimo if a má správnou viditelnost.

Tento kód funguje tak, jak má:

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

Nebo bychom jej mohli ještě více zjednodušit pomocí operátoru otazníku ?:

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

Kdy zvolit deklaraci funkce versus funkční výraz?

Pravidlem je, že pokud potřebujeme deklarovat funkci, jako první přichází v úvahu syntaxe Function Declaration. Dává větší volnost v uspořádání našeho kódu, protože takové funkce můžeme volat ještě před jejich deklarací.

To je také lepší pro čitelnost, protože se v kódu lépe hledá function f(…) {…} než let f = function(…) {…};. Deklarace funkcí je více „na očích“.

…Pokud nám však deklarace funkce z nějakého důvodu nevyhovuje nebo potřebujeme podmíněnou deklaraci (právě jsme viděli příklad), pak je třeba použít funkční výraz.

Shrnutí

  • Funkce jsou hodnoty. Mohou být přiřazeny, zkopírovány nebo deklarovány na libovolném místě kódu.
  • Je-li funkce deklarována jako samostatný příkaz v hlavním toku kódu, nazývá se „Deklarace funkce“.
  • Je-li funkce vytvořena jako součást výrazu, nazývá se „Výraz funkce“.
  • Deklarace funkce jsou zpracovány před provedením bloku kódu. Jsou viditelné všude v bloku.
  • Funkční výrazy se vytvářejí, když k nim dojde tok provádění.

Ve většině případů, kdy potřebujeme deklarovat funkci, je vhodnější Deklarace funkce, protože je viditelná před samotnou deklarací. To nám dává větší flexibilitu v organizaci kódu a obvykle je to čitelnější.

Výraz funkce bychom tedy měli použít pouze tehdy, když se Deklarace funkce pro daný úkol nehodí. V této kapitole jsme viděli několik příkladů a v budoucnu se setkáme s dalšími.

.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.