Funkce v JavaScriptu nenà nÄjaká âmagická jazyková strukturaâ, ale speciálnà druh hodnoty.
Syntaxe, kterou jsme dosud použÃvali, se nazývá deklarace funkce:
function ÅekniAhoj() {
alert( "Ahoj" );
}
Existuje i jiná syntaxe pro vytváÅenà funkce, která se nazývá funkÄnà výraz.
Ten nám umožÅuje vytvoÅit novou funkci uprostÅed libovolného výrazu.
NapÅÃklad:
let ÅekniAhoj = function() {
alert( "Ahoj" );
};
Zde vidÃme promÄnnou ÅekniAhoj, do nÞ je uložena hodnota, kterou je nová funkce, vytvoÅená jako function() { alert("Ahoj"); }.
Protože k vytvoÅenà funkce docházà v kontextu pÅiÅazovacÃho výrazu (na pravé stranÄ =), je to funkÄnà výraz.
ProsÃme vÅ¡imnÄte si, že za klÃÄovým slovem function nenà žádný název. Ve funkÄnÃch výrazech je vynechánà názvu dovoleno.
Zde okamžitÄ pÅiÅazujeme funkci promÄnné, takže význam tohoto pÅÃkladu kódu je stejný: âvytvoÅ funkci a ulož ji do promÄnné ÅekniAhojâ.
V pokroÄilejÅ¡Ãch situacÃch, na které narazÃme pozdÄji, můžeme funkci vytvoÅit a okamžitÄ volat nebo naplánovat jejà pozdÄjšà spuÅ¡tÄnÃ, aniž bychom ji nÄkam uložili, takže funkce zůstane anonymnÃ.
Funkce je hodnota
Zopakujme si: bez ohledu na to, jak je funkce vytvoÅena, funkce je hodnota. V obou výše uvedených pÅÃkladech je funkce uložena do promÄnné ÅekniAhoj.
Tuto hodnotu dokonce můžeme zobrazit pomocà alert:
function ÅekniAhoj() {
alert( "Ahoj" );
}
alert( ÅekniAhoj ); // zobrazà kód funkce
VÅ¡imnÄte si, že poslednà Åádek nevolá funkci, protože za ÅekniAhoj nejsou závorky. Existujà programovacà jazyky, v nichž je funkce zavolána pokaždé, když je uveden jejà název, ale to nenà pÅÃpad JavaScriptu.
V JavaScriptu je funkce hodnota, takže s nà můžeme zacházet jako s hodnotou. Výše uvedený kód zobrazà jejà ÅetÄzcovou reprezentaci, kterou je zdrojový kód funkce.
SamozÅejmÄ, funkce je speciálnà hodnota v tom smyslu, že ji můžeme volat, napÅ. ÅekniAhoj().
Je to však stále hodnota, a proto s nà můžeme pracovat jako s hodnotou jakéhokoli jiného druhu.
Můžeme zkopÃrovat funkci do jiné promÄnné:
function ÅekniAhoj() { // (1) vytvoÅenÃ
alert( "Ahoj" );
}
let funkce = ÅekniAhoj; // (2) zkopÃrovánÃ
funkce(); // Ahoj // (3) spustÃme kopii (funguje to!)
ÅekniAhoj(); // Ahoj // i tohle stále funguje (proÄ by nemÄlo)
Co se v uvedeném pÅÃkladu pÅesnÄ stane:
- Deklarace funkce
(1)vytvoÅà funkci a uložà ji do promÄnné nazvanéÅekniAhoj. - Åádek
(2)ji zkopÃruje do promÄnnéfunkce. OpÄt si vÅ¡imnÄte, že zaÅekniAhojnejsou závorky. Kdyby tam byly, pÅÃkazfunkce = ÅekniAhoj()by zapsal do promÄnnéfunkcevýsledek volánÃÅekniAhoj, ne samotnou funkciÅekniAhoj. - Nynà můžeme tuto funkci volat pomocÃ
ÅekniAhoj()i pomocÃfunkce().
Na prvnÃm Åádku jsme mohli deklarovat ÅekniAhoj i pomocà funkÄnÃho výrazu:
let ÅekniAhoj = function() { // (1) vytvoÅenÃ
alert( "Ahoj" );
};
let funkce = ÅekniAhoj; // (2)
// ...
VÅ¡echno bude fungovat stejnÄ.
Možná se divÃte, proÄ funkÄnà výraz obsahuje na konci stÅednÃk ;, ale deklarace funkce ne:
function ÅekniAhoj() {
// ...
}
let ÅekniAhoj = function() {
// ...
};
OdpovÄÄ je jednoduchá: funkÄnà výraz je zde vytvoÅen jako function(â¦) {â¦} uvnitÅ pÅÃkazu pÅiÅazenÃ: let ÅekniAhoj = â¦;. StÅednÃk ; se doporuÄuje uvádÄt na konci pÅÃkazu, nenà to souÄást syntaxe funkce.
StÅednÃk by zde byl i u jednoduššÃho pÅiÅazenÃ, napÅÃklad let ÅekniAhoj = 5;, a je zde také u pÅiÅazenà funkce.
Funkce zpÄtného volánà (callbackové funkce)
PodÃváme se na dalšà pÅÃklady pÅedávánà funkcà jako hodnot a použÃvánà funkÄnÃch výrazů.
NapÃÅ¡eme funkci zeptejSe(otázka, ano, ne) se tÅemi parametry:
otázka- Text otázky
ano- Funkce, která se spustÃ, je-li odpovÄÄ âanoâ
ne- Funkce, která se spustÃ, je-li odpovÄÄ âneâ
Funkce by mÄla položit otázku otázka a pak podle odpovÄdi uživatele zavolat ano() nebo ne():
function zeptejSe(otázka, ano, ne) {
if (confirm(otázka)) ano()
else ne();
}
function zobrazOK() {
alert( "Souhlasil jste." );
}
function zobrazStorno() {
alert( "ZruÅ¡il jste provádÄnÃ." );
}
// použitÃ: funkce zobrazOK, zobrazStorno jsou pÅedány funkci zeptejSe jako argumenty
zeptejSe("SouhlasÃte?", zobrazOK, zobrazStorno);
V praxi jsou takové funkce pomÄrnÄ užiteÄné. HlavnÃm rozdÃlem mezi zeptejSe ve skuteÄném životÄ a uvedeným pÅÃkladem je, že skuteÄné funkce použÃvajà složitÄjšà způsoby interakce s uživatelem, než pouhé confirm. V prohlÞeÄi taková funkce obvykle vykreslà pÄkné dotazovacà okno. To je vÅ¡ak jiný pÅÃbÄh.
Argumenty zobrazOK a zobrazStorno funkce zeptejSe se nazývajà callbackové funkce nebo jednoduše callbacky.
MyÅ¡lenkou je, že pÅedáme funkci a oÄekáváme, že bude âzpÄtnÄ volánaâ (call = volánÃ, back = zpÄt) pozdÄji, až to bude nutné. V naÅ¡em pÅÃpadÄ zobrazOK se stala callbackem pro odpovÄÄ âanoâ a zobrazStorno pro odpovÄÄ âneâ.
Pomocà funkÄnÃch výrazů můžeme napsat ekvivalentnÃ, ale kratšà funkci:
function zeptejSe(otázka, ano, ne) {
if (confirm(otázka)) ano()
else ne();
}
zeptejSe(
"SouhlasÃte?",
function() { alert("Souhlasil jste."); },
function() { alert("ZruÅ¡il jste provádÄnÃ."); }
);
Zde jsou funkce deklarovány pÅÃmo ve volánà zeptejSe(...). Nemajà žádný název, a tak se nazývajà anonymnÃ. Takové funkce nejsou dostupné mimo zeptejSe (protože nejsou pÅiÅazeny žádným promÄnným), ale to je pÅesnÄ to, co tady chceme.
Takový kód se v naÅ¡ich skriptech objevuje zcela pÅirozenÄ a je pÅesnÄ v duchu JavaScriptu.
BÄžné hodnoty, napÅ. ÅetÄzce nebo ÄÃsla, pÅedstavujà data.
Na funkci lze pohlÞet jako na akci.
Můžeme ji pÅedávat mezi promÄnnými a zavolat, až budeme chtÃt.
FunkÄnà výrazy vs. deklarace funkcÃ
Zformulujme nynà základnà rozdÃly mezi deklaracemi funkcà a funkÄnÃmi výrazy.
Prvnà rozdÃl je syntaxe: jak je rozliÅ¡ovat v kódu.
-
Deklarace funkce: funkce deklarovaná samostatným pÅÃkazem v hlavnÃm toku kódu:
// deklarace funkce function souÄet(a, b) { return a + b; } -
FunkÄnà výraz: funkce vytvoÅená uprostÅed výrazu nebo uvnitÅ jiného syntaktického konstruktu. Zde je funkce vytvoÅena na pravé stranÄ âoperátoru pÅiÅazenÃâ
=:// funkÄnà výraz let souÄet = function(a, b) { return a + b; };
JemnÄjšà rozdÃl spoÄÃvá v tom, kdy pÅesnÄ je funkce vytvoÅena enginem JavaScriptu.
FunkÄnà výraz je vytvoÅen ve chvÃli, kdy k nÄmu dospÄje vykonávánà kódu, a je použitelný až od této chvÃle.
Jakmile se provádÄnà skriptu dostane k pravé stranÄ pÅiÅazenà let souÄet = function⦠â v tom okamžiku je funkce vytvoÅena a od nynÄjÅ¡ka může být použÃvána (pÅiÅazena, volána apod.).
Deklarace funkcà jsou odlišné.
Deklarovaná funkce může být volána jeÅ¡tÄ dÅÃve, než je definována.
NapÅÃklad globálnà deklarace funkce je viditelná v celém skriptu, aÅ¥ se nacházà kdekoli.
Je to způsobeno vnitÅnÃmi algoritmy. Když JavaScript pÅipravuje spuÅ¡tÄnà skriptu, nejprve v nÄm najde globálnà deklarace funkcà a tyto funkce vytvoÅÃ. Můžeme to považovat za âpÅÃpravnou fáziâ.
Teprve až jsou vÅ¡echny deklarace funkcà zpracovány, kód se vykoná. Proto má k tÄmto funkcÃm pÅÃstup.
NapÅÃklad toto funguje:
ÅekniAhoj("Jan"); // Ahoj, Jan
function ÅekniAhoj(jméno) {
alert( `Ahoj, ${jméno}` );
}
Deklarace funkce ÅekniAhoj se vytvoÅÃ, když JavaScript pÅipravuje spuÅ¡tÄnà skriptu, a je v nÄm vÅ¡ude viditelná.
â¦Kdyby to vÅ¡ak byl funkÄnà výraz, nefungovalo by to:
ÅekniAhoj("Jan"); // chyba!
let ÅekniAhoj = function(jméno) { // (*) už žádná magie
alert( `Ahoj, ${jméno}` );
};
FunkÄnà výrazy se vytvoÅÃ, když k nim dorazà vykonávánà kódu. To se stane až na Åádku (*). PozdÄ.
Dalšà speciálnà vlastnostà deklaracà funkcà je blok jejich platnosti.
Ve striktnÃm režimu platÃ, že když je deklarace funkce umÃstÄna v bloku kódu, je viditelná vÅ¡ude uvnitÅ tohoto bloku, ale ne mimo nÄj.
NapÅÃklad si pÅedstavme, že potÅebujeme deklarovat funkci uvÃtánÃ(), která závisà na promÄnné vÄk, kterou zÃskáme za bÄhu skriptu. A pak ji plánujeme použÃt o nÄco pozdÄji.
Kdybychom použili deklaraci funkce, nefungovalo by to tak, jak zamýšlÃme:
let vÄk = prompt("Kolik je vám let?", 18);
// podmÃnÄná deklarace funkce
if (vÄk < 18) {
function uvÃtánÃ() {
alert("Ahoj!");
}
} else {
function uvÃtánÃ() {
alert("Dobrý den!");
}
}
// ...použijeme ji pozdÄji
uvÃtánÃ(); // Chyba: uvÃtánà nenà definováno
Je to proto, že deklarace funkce je viditelná jedinÄ uvnitÅ bloku kódu, v nÄmž se nacházÃ.
Dalšà pÅÃklad:
let vÄk = 16; // vezmeme 16 jako pÅÃklad
if (vÄk < 18) {
uvÃtánÃ(); // \ (spustà se)
// |
function uvÃtánÃ() { // |
alert("Ahoj!"); // | deklarace funkce je k dispozici
} // | vÅ¡ude v bloku, v nÄmž je funkce deklarována
// |
uvÃtánÃ(); // / (spustà se)
} else {
function uvÃtánÃ() {
alert("ZdravÃme vás!");
}
}
// Tady už jsme mimo složené závorky,
// takže nevidÃme deklarace funkcÃ, které se nacházejà uvnitÅ nich.
uvÃtánÃ(); // Chyba: uvÃtánà nenà definováno
Jak můžeme uvÃtánà uÄinit viditelným i mimo if?
Správný pÅÃstup by byl použità funkÄnÃho výrazu a pÅiÅazenà uvÃtánà do promÄnné, která je deklarována mimo if a má náležitou viditelnost.
Tento kód funguje tak, jak zamýšlÃme:
let vÄk = prompt("Kolik je vám let?", 18);
let uvÃtánÃ;
if (vÄk < 18) {
uvÃtánà = function() {
alert("Ahoj!");
};
} else {
uvÃtánà = function() {
alert("Dobrý den!");
};
}
uvÃtánÃ(); // nynà je to v poÅádku
Nebo to můžeme jeÅ¡tÄ zjednoduÅ¡it pomocà operátoru otaznÃku ?:
let vÄk = prompt("Kolik je vám let?", 18);
let uvÃtánà = (vÄk < 18) ?
function() { alert("Ahoj!"); } :
function() { alert("Dobrý den!"); };
uvÃtánÃ(); // nynà je to v poÅádku
OrientaÄnà pravidlo znÃ, že když potÅebujeme deklarovat funkci, mÄli bychom napÅed zvážit syntaxi deklarace funkce. Ta nám dává vÃce svobody v tom, jak zorganizovat kód, protože takovou funkci můžeme volat jeÅ¡tÄ pÅedtÃm, než je deklarována.
Je také lépe Äitelná, protože je jednoduššà najÃt v kódu function f(â¦) {â¦} než let f = function(â¦) {â¦};. Deklarace funkcà lépe âpadnou do okaâ.
â¦Jestliže nám vÅ¡ak deklarace funkce pro naÅ¡e úÄely nestaÄà nebo potÅebujeme podmÃnÄnou deklaraci (jak jsme právÄ vidÄli v pÅÃkladu), mÄli bychom použÃt funkÄnà výraz.
ShrnutÃ
- Funkce jsou hodnoty. Kdekoli v kódu je můžeme pÅiÅazovat, kopÃrovat nebo deklarovat.
- Je-li funkce deklarována samostatným pÅÃkazem v hlavnÃm kódu, nazývá se to âdeklarace funkceâ.
- Je-li funkce vytvoÅena jako souÄást výrazu, nazývá se to âfunkÄnà výrazâ.
- Deklarace funkcà se zpracovávajà jeÅ¡tÄ pÅedtÃm, než je blok kódu vykonán. Jsou tedy viditelné vÅ¡ude v celém bloku.
- FunkÄnà výrazy se vytvoÅà až ve chvÃli, kdy k nim dorazà výkon kódu.
Ve vÄtÅ¡inÄ pÅÃpadů, kdy potÅebujeme deklarovat funkci, dáváme pÅednost deklaraci funkce, protože pak je funkce viditelná jeÅ¡tÄ pÅed samotnou deklaracÃ. To nám dává vÃce možnostà pÅi organizaci kódu a je to zpravidla ÄitelnÄjÅ¡Ã.
FunkÄnà výrazy bychom tedy mÄli použÃvat jen tehdy, když nám pro naÅ¡e úÄely deklarace funkce nestaÄÃ. V této kapitole jsme vidÄli nÄkolik takových pÅÃkladů a v budoucnu uvidÃme dalÅ¡Ã.
KomentáÅe
<code>, pro nÄkolik Åádků je obalte znaÄkou<pre>, pro vÃce než 10 Åádků vložte odkaz na pÃskoviÅ¡tÄ (plnkr, jsbin, codepenâ¦)