Funkce JavaScriptu. Expresivní JavaScript: Funkce JavaScriptu vracející více hodnot z funkce

Lidé si myslí, že informatika je umění pro génia. Ve skutečnosti je to naopak – jen spousta lidí vyrábí věci, které stojí na sobě, jako by tvořily stěnu z malých oblázků.

Donald Knuth

Volání funkcí, jako je upozornění, jste již viděli. Funkce jsou chlebem a máslem programování v JavaScriptu. Myšlenka zabalit část programu a nazvat ji jako proměnnou je velmi populární. Je to nástroj pro strukturování velkých programů, omezení opakování, pojmenování podprogramů a oddělení podprogramů od sebe navzájem.

Nejviditelnější použití funkcí je vytvoření nového slovníku. Vymýšlet slova pro běžnou lidskou prózu je špatná forma. To je nutné v programovacím jazyce.

Průměrný dospělý ruský mluvčí zná přibližně 10 000 slov. Vzácný programovací jazyk obsahuje 10 000 vestavěných příkazů. A slovní zásoba programovacího jazyka je jasněji definovaná, takže je méně flexibilní než lidský. Proto k němu většinou musíme přidat vlastní slova, abychom se vyhnuli zbytečnému opakování.

Definice funkce Definice funkce je definice normální proměnné, kde hodnota, kterou proměnná přijímá, je funkce. Například následující kód definuje proměnnou čtverec, který odkazuje na funkci, která vypočítá druhou mocninu daného čísla:

Var square = funkce(x) ( return x * x; ); console.log(čtverec(12)); // → 144

Funkce je vytvořena výrazem začínajícím klíčovým slovem function. Funkce mají sadu parametrů (v tomto případě pouze x) a tělo obsahující instrukce, které musí být provedeny při volání funkce. Tělo funkce je vždy uzavřeno ve složených závorkách, i když se skládá z jediného příkazu.

Funkce může mít několik parametrů nebo žádný. V následujícím příkladu makeNoise nemá seznam parametrů, ale výkon má dva:

Var makeNoise = function() ( console.log("Hovno!"); ); dělat hluk(); // → Khrya! var mocnina = funkce (základ, exponent) ( var výsledek = 1; pro (počet var = 0; počet< exponent; count++) result *= base; return result; }; console.log(power(2, 10)); // → 1024

Některé funkce vracejí hodnotu, jako je mocnina a čtverec, jiné ne, jako makeNoise, což má pouze vedlejší efekt. Příkaz return určuje hodnotu vrácenou funkcí. Když programové zpracování dosáhne této instrukce, okamžitě funkci opustí a vrátí tuto hodnotu na místo v kódu, ze kterého byla funkce volána. return bez výrazu vrací undefined .

Parametry a rozsah Parametry funkce jsou stejné proměnné, ale jejich počáteční hodnoty jsou nastaveny při volání funkce, nikoli v jejím kódu.

Důležitou vlastností funkcí je, že proměnné vytvořené v rámci funkce (včetně parametrů) jsou pro tuto funkci lokální. To znamená, že v mocenském příkladu bude výsledná proměnná vytvořena při každém volání funkce a tyto její jednotlivé inkarnace spolu nebudou mít nic společného.

Toto umístění proměnné se vztahuje pouze na parametry a proměnné vytvořené v rámci funkcí. Proměnné definované mimo jakoukoli funkci se nazývají globální, protože jsou viditelné v celém programu. K takovým proměnným můžete také přistupovat uvnitř funkce, pokud nedeklarujete lokální proměnnou se stejným názvem.

Následující kód to ilustruje. Definuje a volá dvě funkce, které přiřazují hodnotu proměnné x. První ji deklaruje jako lokální, čímž změní pouze lokální proměnnou. Druhý nedeklaruje, takže práce s x uvnitř funkce odkazuje na globální proměnnou x definovanou na začátku příkladu.

Var x = "venku"; var f1 = function() ( var x = "uvnitř f1"; ); f1(); console.log(x); // → vně var f2 = function() ( x = "uvnitř f2"; ); f2(); console.log(x); // → uvnitř f2

Toto chování pomáhá předcházet náhodným interakcím mezi funkcemi. Pokud by byly všechny proměnné použity kdekoli v programu, bylo by velmi obtížné zajistit, aby jedna proměnná nebyla použita pro různé účely. A pokud byste proměnnou znovu použili, narazili byste na podivné efekty, když kód třetí strany poškodil hodnoty vaší proměnné. Tím, že jazyk zachází s funkčními lokálními proměnnými tak, že existují pouze v rámci funkce, umožňuje pracovat s funkcemi, jako by to byly samostatné malé vesmíry, což vám umožňuje nestarat se o celý kód.

Vnořený JavaScript rozlišuje více než jen mezi globálními a lokálními proměnnými. Funkce mohou být definovány v rámci funkcí, což vede k více úrovním lokality.

Například následující poněkud nesmyslná funkce obsahuje uvnitř další dvě:

Var landscape = function() ( var result = ""; var flat = function(size) ( for (var count = 0; count< size; count++) result += "_"; }; var mountain = function(size) { result += "/"; for (var count = 0; count < size; count++) result += """; result += "\\"; }; flat(3); mountain(4); flat(6); mountain(1); flat(1); return result; }; console.log(landscape()); // → ___/""""\______/"\_

Funkce rovina a hora vidí výslednou proměnnou, protože jsou uvnitř funkce, která ji definuje. Nemohou však navzájem vidět početní proměnné, protože proměnné jedné funkce jsou mimo rozsah druhé. A prostředí mimo krajinnou funkci nevidí žádnou z proměnných definovaných uvnitř této funkce.

Stručně řečeno, v rámci každého místního rozsahu můžete vidět všechny rozsahy, které jej obsahují. Sada proměnných dostupných v rámci funkce je určena umístěním, kde je funkce deklarována v programu. Všechny proměnné z bloků obklopujících definici funkce jsou viditelné – včetně těch, které jsou definovány na nejvyšší úrovni v hlavním programu. Tento přístup k oborům se nazývá lexikální.

Lidé, kteří studovali jiné programovací jazyky, si mohou myslet, že jakýkoli blok uzavřený ve složených závorkách vytváří své vlastní místní prostředí. Ale v JavaScriptu vytvářejí rozsah pouze funkce. Volně stojící bloky můžete použít:

Var něco = 1; ( var something = 2; // Udělejte něco s proměnnou something... ) // Opustil blok...

Ale něco uvnitř bloku je stejná proměnná jako venku. Ačkoli jsou takové bloky povoleny, má smysl je používat pouze pro příkazy if a smyčky.

Pokud se vám to zdá divné, nejste jediný, komu to připadá. Ve verzi se objevil JavaScript 1.7 klíčové slovo let, který funguje jako var, ale vytváří proměnné, které jsou lokální pro jakýkoli daný blok, nejen pro funkci.

Funkce jako hodnoty Názvy funkcí se obvykle používají jako název části programu. Taková proměnná je nastavena jednou a nemění se. Je tedy snadné zaměnit funkci a její název.

Ale to jsou dvě různé věci. Volání funkce lze použít jako jednoduchou proměnnou – například v libovolném výrazu. Je možné uložit volání funkce do nové proměnné, předat ji jako parametr jiné funkci a podobně. Také proměnná ukládající volání funkce zůstává běžnou proměnnou a její hodnotu lze změnit:

Var launchMissiles = function(value) ( ​​​​missileSystem.launch("nebo!"); ); if (safeMode) launchMissiles = function(value) (/* cancel */);

V kapitole 5 probereme úžasné věci, které můžete udělat předáním volání funkcí jiným funkcím.

Deklarace funkcí Existuje kratší verze výrazu „var square = funkce...“. Klíčové slovo funkce lze použít na začátku příkazu:

Funkce square(x) ( return x * x; )

Toto je deklarace funkce. Příkaz definuje čtvercovou proměnnou a přiřadí jí danou funkci. Zatím je vše dobré. V takové definici je pouze jedno úskalí.

Console.log("Budoucnost říká:", future()); function future() ( return "STÁLE nemáme létající auta."; )

Tento kód funguje, i když je funkce deklarována pod kódem, který ji používá. Je to proto, že deklarace funkcí nejsou součástí běžného provádění programu shora dolů. Jsou „přesunuty“ na vrchol svého rozsahu a mohou být volány jakýmkoli kódem v tomto rozsahu. Někdy je to výhodné, protože můžete psát kód v pořadí, které dává největší smysl, aniž byste se museli starat o to, abyste museli definovat všechny výše uvedené funkce, kde se používají.

Co se stane, když umístíme deklaraci funkce do podmíněného bloku nebo smyčky? Nemusíte to dělat. Historicky různé platformy s JavaScriptem řešily takové případy odlišně a současný jazykový standard to zakazuje. Pokud chcete, aby se vaše programy spouštěly sekvenčně, použijte deklarace funkcí pouze v rámci jiných funkcí nebo hlavního programu.

Příklad funkce() ( funkce a() () // Normální if (něco) ( funkce b() () // Ay-yay-yay! ) )

Zásobník volání Je užitečné podívat se blíže na to, jak příkaz k provedení pracuje s funkcemi. Tady jednoduchý program s voláním více funkcí:

Funkce pozdrav(kdo) ( console.log("Ahoj, " + kdo); ) pozdrav("Semyon"); console.log("Pokeda");

Zpracovává se asi takto: volání pozdravu způsobí skok na začátek funkce. Volá vestavěnou funkci console.log, která zachytí řízení, udělá svou věc a vrátí řízení. Poté se dostane na konec pozdravu a vrátí se na místo, odkud byl volán. Další řádek znovu volá console.log.

Schematicky to lze znázornit takto:

Top pozdrav console.log pozdrav top console.log top

Protože se funkce musí vrátit na místo, odkud byla volána, musí si počítač pamatovat kontext, ze kterého byla funkce volána. V jednom případě by se měl console.log vrátit zpět a pozdravit. V jiném se vrací na konec programu.

Místo, kde si počítač pamatuje kontext, se nazývá zásobník. Při každém volání funkce se aktuální kontext přesune na začátek zásobníku. Když se funkce vrátí, vyskočí ze zásobníku horní kontext a použije jej k pokračování v běhu.

Zásobníkové úložiště vyžaduje místo v paměti. Když se zásobník příliš zvětší, počítač přestane provádět a řekne něco jako „přetečení zásobníku“ nebo „příliš mnoho rekurze“. Následující kód to demonstruje – klade počítači velmi složitou otázku, která vede k nekonečným skokům mezi dvěma funkcemi. Přesněji by to byly nekonečné skoky, pokud by počítač měl nekonečný zásobník. Ve skutečnosti zásobník přeteče.

Funkce chicken() ( return egg(); ) function egg() ( return chicken(); ) console.log(chicken() + "přišel jako první."); // → ??

Volitelné argumenty Následující kód je zcela legální a běží bez problémů:

Alert("Ahoj", "Dobrý večer", "Ahoj všichni!");

Oficiálně má funkce jeden argument. Když je však takto vyzvána, nestěžuje si. Ignoruje zbytek argumentů a ukáže "Ahoj."

JavaScript je velmi specifický, pokud jde o počet argumentů předávaných funkci. Pokud přenesete příliš mnoho, přebytečné položky budou ignorovány. Příliš málo a chybějícím bude přiřazena hodnota nedefinovaná.

Nevýhodou tohoto přístupu je, že je možné – a dokonce pravděpodobné – předat funkci nesprávný počet argumentů, aniž by si na to někdo stěžoval.

Výhodou je, že můžete vytvářet funkce, které přebírají volitelné argumenty. Například v další verzi mocninné funkce ji lze volat buď se dvěma, nebo jedním argumentem – v druhém případě bude exponent roven dvěma a funkce funguje jako čtverec.

Mocnina funkce (základ, exponent) ( if (exponent == nedefinováno) exponent = 2; výsledek var = 1; pro (počet var = 0; počet< exponent; count++) result *= base; return result; } console.log(power(4)); // → 16 console.log(power(4, 3)); // → 64

V další kapitole uvidíme, jak můžete v těle funkce zjistit přesný počet argumentů, které jí byly předány. To je užitečné, protože... umožňuje vytvořit funkci, která přebírá libovolný počet argumentů. Například console.log používá tuto vlastnost a vypisuje všechny argumenty, které mu byly předány:

Console.log("R", 2, "D", 2); // → R 2 D 2

Závěry Schopnost používat volání funkcí jako proměnné spolu se skutečností, že lokální proměnné jsou vytvářeny znovu při každém volání funkce, nás vede k zajímavé otázce. Co se stane s lokálními proměnnými, když funkce přestane fungovat?

Následující příklad ilustruje tento problém. Deklaruje funkci wrapValue, která vytvoří lokální proměnnou. Poté vrátí funkci, která přečte tuto lokální proměnnou a vrátí její hodnotu.

Funkce wrapValue(n) ( var localVariable = n; return function() ( return localVariable; ); ) var wrap1 = wrapValue(1); var wrap2 = wrapValue(2); console.log(wrap1()); // → 1 console.log(wrap2()); // → 2

To platí a funguje jak má – přístup k proměnné zůstává. Kromě toho může současně existovat více instancí stejné proměnné, což dále potvrzuje skutečnost, že místní proměnné jsou znovu vytvořeny s každým voláním funkce.

Tato schopnost pracovat s odkazem na instanci lokální proměnné se nazývá uzávěr. Funkce, která uzavírá lokální proměnné, se nazývá uzávěr. Nejen, že vás zbaví starostí s proměnlivou životností, ale také vám umožní používat funkce kreativně.

S mírnou úpravou převedeme náš příklad do funkce, která násobí čísla libovolným daným číslem.

Funkce multiplikátor(faktor) ( return function(number) ( return number * factor; ); ) var double = multiplier(2); console.log(dvakrát(5)); // → 10

Samostatná proměnná jako localVariable z příkladu wrapValue již není potřeba. Protože parametr je sám o sobě lokální proměnnou.

Bude to vyžadovat praxi, abyste začali takto přemýšlet. Dobrá volba mentálním modelem je představit si, že funkce zmrazí kód ve svém těle a zabalí jej do obalu. Když uvidíte funkci return(...) (...), představte si ji jako ovládací panel pro část kódu zmrazenou pro pozdější použití.

V našem příkladu vrací multiplikátor zmrazený kus kódu, který uložíme do proměnné double. Poslední řádek volá funkci obsaženou v proměnné, která způsobí aktivaci uloženého kódu (návratové číslo * faktor;). Stále má přístup k proměnné faktor, která byla definována při volání multiplikátoru, a má také přístup k argumentu předávanému během odmrazování (5) jako číselnému parametru.

Rekurze Funkce může volat sama sebe, pokud se stará o to, aby nepřetekla zásobník. Tato funkce se nazývá rekurzivní. Zde je příklad alternativní implementace umocňování:

Funkce power(základ, exponent) ( if (exponent == 0) return 1; else return base * power(base, exponent - 1); ) console.log(power(2, 3)); // → 8

Zhruba takto matematici definují umocňování a možná to tento koncept popisuje elegantněji než cyklus. Funkce volá sama sebe mnohokrát s různými argumenty, aby se dosáhlo vícenásobného násobení.

S touto implementací je však problém: normální prostředí JavaScript je 10x pomalejší než verze se smyčkou. Procházení smyčkou je levnější než volání funkce.

Dilema rychlost versus elegance je docela zajímavé. Existuje určitá propast mezi pohodlím pro lidi a pohodlím pro stroje. Jakýkoli program lze urychlit tím, že bude větší a složitější. Programátor je povinen najít vhodnou rovnováhu.

V případě prvního umocnění je neelegantní smyčka celkem jednoduchá a přímočará. Nemá smysl to nahrazovat rekurzí. Často se však programy zabývají tak složitými pojmy, že člověk chce snížit efektivitu zvýšením čitelnosti.

Základním nejednou opakovaným pravidlem, se kterým naprosto souhlasím, je nestarat se o výkon, dokud si nebudete naprosto jisti, že se program zpomaluje. Pokud ano, najděte díly, které vydrží nejdéle, a vyměňte eleganci za efektivitu tam.

Samozřejmě bychom neměli hned úplně ignorovat výkon. V mnoha případech, stejně jako u umocňování, z elegantních řešení mnoho jednoduchosti nezískáme. Někdy zkušený programátor okamžitě vidí, že jednoduchý přístup nebude nikdy dost rychlý.

Upozorňuji na to, protože příliš mnoho začínajících programátorů je posedlých efektivitou i v malých věcech. Výsledek je větší, složitější a často není bez chyb. Takové programy se zapisují déle, ale často nepracují mnohem rychleji.

Ale rekurze není vždy jen méně efektivní alternativou smyček. Některé problémy se snáze řeší rekurzí. Nejčastěji se jedná o procházení několika větví stromu, z nichž každá se může větvit.

Zde je hádanka: nekonečný počet čísel můžete získat tak, že začnete číslem 1 a pak buď sečtete 5, nebo vynásobíte 3. Jak napíšeme funkci, která se při daném čísle snaží najít posloupnost sčítání a násobení které vedou k danému číslu? Například číslo 13 lze získat tak, že nejprve vynásobíte 1 3 a poté dvakrát přičtete 5. A číslo 15 takto získat vůbec nejde.

Rekurzivní řešení:

Funkce findSolution(target) ( funkce find(start, historie) ( if (start == target) return history; else if (start > target) return null; else return find (start + 5, "(" + history + " + 5)") || find(start * 3, "(" + historie + " * 3)"); ) return find(1, "1"); ) console.log(findSolution(24)); // → (((1 * 3) + 5) * 3)

Tento příklad nemusí nutně najít nejkratší řešení – vyhovuje mu jakékoli. Neočekávám, že okamžitě pochopíte, jak program funguje. Ale pojďme pochopit toto skvělé cvičení v rekurzivním myšlení.

Vnitřní funkce find provádí rekurzi. Vyžaduje dva argumenty – aktuální číslo a řetězec, který obsahuje záznam, jak jsme k tomuto číslu dospěli. A vrací buď řetězec ukazující naši sekvenci kroků, nebo null.

K tomu funkce provede jednu ze tří akcí. Pokud se dané číslo rovná cíli, pak aktuální příběh je právě způsob, jak toho dosáhnout, takže se vrací. Pokud je dané číslo větší než cíl, nemá smysl dále násobit a sčítat, protože se bude jen zvyšovat. A pokud jsme ještě nedosáhli cíle, funkce zkouší obojí možné způsoby, počínaje daným číslem. Přivolá se dvakrát, jednou pro každou metodu. Pokud první volání nevrátí hodnotu null, je vráceno. V jiném případě se vrátí druhý.

Abychom lépe pochopili, jak funkce dosahuje požadovaného účinku, podívejme se na volání, která provádí, abychom našli řešení pro číslo 13.

Find(1; "1") find(6, "(1 + 5)") find(11, "((1 + 5) + 5)") find(16, "((1 + 5) + 5 ) + 5)") příliš velký nález(33, "(((1 + 5) + 5) * 3)") příliš velký nález(18, "((1 + 5) * 3)") příliš velký nález( 3, "(1 * 3)") najít (8, "(1 * 3) + 5)") najít (13, "(((1 * 3) + 5) + 5)") nalezeno!

Odsazení ukazuje hloubku zásobníku volání. Poprvé se funkce find zavolá dvakrát, aby zkontrolovala řešení začínající na (1 + 5) a (1 * 3). První volání hledá řešení začínající na (1 + 5) a pomocí rekurze kontroluje všechna řešení, která vytvářejí číslo menší nebo rovné požadovanému číslu. Nenajde a vrátí hodnotu null. Potom operátor || a přejde k volání funkce, která zkoumá volbu (1 * 3). Zde máme štěstí, protože ve třetím rekurzivním volání dostaneme 13. Toto volání vrátí řetězec a každý z || po cestě míjí tuto čáru výše, což má za následek návrat řešení.

Rostoucí funkce Existují dva víceméně přirozené způsoby, jak zavést funkce do programu.

První je, že podobný kód napíšete několikrát. Tomu je třeba se vyhnout – více kódu znamená více prostoru pro chyby a více materiálu pro čtení pro ty, kteří se snaží program pochopit. Vezmeme tedy opakující se funkci a přizpůsobíme ji dobré jméno a dát to do funkce.

Druhým způsobem je, že objevíte potřebu nějaké nové funkce, která stojí za to umístit do samostatné funkce. Začnete názvem funkce a poté napíšete její tělo. Můžete dokonce začít napsáním kódu, který funkci používá, ještě předtím, než byla funkce samotná definována.

Jak obtížné je pro vás funkci pojmenovat, ukazuje, jak dobře rozumíte její funkčnosti. Vezměme si příklad. Potřebujeme napsat program, který vypíše dvě čísla, počet krav a kuřat na farmě, za nimiž budou následovat slova „krávy“ a „kuřata“. K číslům vpředu je třeba přidat nuly, aby každé obsadilo právě tři pozice.

007 Krávy 011 Kuřata

Je zřejmé, že potřebujeme funkci se dvěma argumenty. Začněme kódovat.
// tisk funkce FarmInventory printFarmInventory(krávy, kuřata) ( var cowString = String(krávy); while (cowString.length< 3) cowString = "0" + cowString; console.log(cowString + " Коров"); var chickenString = String(chickens); while (chickenString.length < 3) chickenString = "0" + chickenString; console.log(chickenString + " Куриц"); } printFarmInventory(7, 11);

Pokud k řetězci přidáme .length, dostaneme jeho délku. Ukázalo se, že zatímco smyčky přidávejte k číslům úvodní nuly, dokud nezískáte tříznakový řetězec.

Připraveno! Ale právě když jsme se chystali poslat kód farmáři (samozřejmě spolu s tučnou kontrolou), zavolá a řekne nám, že má na farmě prasata a mohli bychom přidat zobrazení počtu prasat do program?

Samozřejmě je to možné. Ale když začneme kopírovat a vkládat kód z těchto čtyř řádků, uvědomíme si, že se musíme zastavit a přemýšlet. Musí existovat lepší způsob. Snažíme se program vylepšit:

// výstup WITH funkce přidávání nul A štítků printZeroPaddedWithLabel(číslo, štítek) ( var numberString = String(číslo); while (numberString.length< 3) numberString = "0" + numberString; console.log(numberString + " " + label); } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { printZeroPaddedWithLabel(cows, "Коров"); printZeroPaddedWithLabel(chickens, "Куриц"); printZeroPaddedWithLabel(pigs, "Свиней"); } printFarmInventory(7, 11, 3);

Funguje! Název printZeroPaddedWithLabel je ale trochu zvláštní. Spojuje tři věci – výstup, přidávání nul a štítek – do jedné funkce. Namísto vkládání celého opakujícího se fragmentu do funkce zdůrazněme jeden koncept:

// přidání funkce nula zeroPad(číslo, šířka) ( var string = String(číslo); while (string.length< width) string = "0" + string; return string; } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { console.log(zeroPad(cows, 3) + " Коров"); console.log(zeroPad(chickens, 3) + " Куриц"); console.log(zeroPad(pigs, 3) + " Свиней"); } printFarmInventory(7, 16, 3);

Funkce s pěkným a jasným názvem zeroPad usnadňuje pochopení kódu. A dá se použít v mnoha situacích, nejen v našem případě. Například pro zobrazení formátovaných tabulek s čísly.

Jak chytré a univerzální by měly být funkce? Můžeme napsat buď jednoduchou funkci, která doplní číslo nulami až na tři pozice, nebo sofistikovanou funkci obecný účel pro formátování čísel, podporu zlomků, záporných čísel, zarovnání teček, vyplnění různými znaky atd.

Dobrým pravidlem je přidávat pouze funkce, o kterých víte, že budou užitečné. Někdy je lákavé vytvořit univerzální rámce pro každou malou potřebu. Odolejte mu. Práci nikdy nedokončíte, jen skončíte u psaní hromady kódů, které nikdo nepoužije.

Funkce a vedlejší účinky Funkce lze zhruba rozdělit na ty, které jsou volány kvůli jejich vedlejším účinkům, a ty, které jsou volány, aby získaly nějakou hodnotu. Samozřejmě je také možné tyto vlastnosti kombinovat v jedné funkci.

První pomocná funkce v příkladu farmy, printZeroPaddedWithLabel, se nazývá, protože má vedlejší účinek: vytiskne řetězec. Druhý, zeroPad, kvůli návratové hodnotě. A není náhoda, že druhá funkce se hodí častěji než ta první. Funkce, které vracejí hodnoty, se dají snáze kombinovat než funkce, které mají vedlejší účinky.

Čistá funkce je speciální druh funkce vracející hodnotu, která nejenže nemá žádné vedlejší účinky, ale také nezávisí na vedlejších účincích zbytku kódu – například nepracuje s globálními proměnnými, které by mohly být náhodně změnili někde jinde. Čistá funkce, když je volána se stejnými argumenty, vrací stejný výsledek (a nedělá nic jiného) - což je docela příjemné. Snadno se s ní pracuje. Volání takové funkce může být mentálně nahrazeno výsledkem její práce, aniž by se změnil význam kódu. Když chcete takovou funkci otestovat, můžete ji jednoduše zavolat a být si jisti, že pokud funguje v daném kontextu, bude fungovat v jakémkoli kontextu. Méně čisté funkce mohou vracet různé výsledky v závislosti na mnoha faktorech a mít vedlejší účinky, které se obtížně testují a zohledňují.

Neměli byste se však stydět napsat funkce, které nejsou zcela čisté, nebo začít s posvátným kódovým čištěním takových funkcí. Vedlejší účinky jsou často prospěšné. Neexistuje způsob, jak napsat čistou verzi funkce console.log a tato funkce je docela užitečná. Některé operace lze snadněji vyjádřit pomocí vedlejších účinků.

Shrnutí Tato kapitola vám ukázala, jak psát své vlastní funkce. Když je klíčové slovo funkce použito jako výraz, vrátí ukazatel na volání funkce. Při použití jako instrukce můžete proměnnou deklarovat tak, že jí přiřadíte volání funkce.

Klíčem k pochopení funkcí je místní rozsah. Parametry a proměnné deklarované uvnitř funkce jsou pro ni lokální, jsou znovu vytvořeny při každém jejím volání a nejsou zvenčí viditelné. Funkce deklarované uvnitř jiné funkce mají přístup k jejímu rozsahu.

Je velmi užitečné rozdělit různé úkoly prováděné programem do funkcí. Nemusíte se opakovat, funkce dělají kód čitelnějším tím, že jej rozdělují na smysluplné části, stejně jako kapitoly a části knihy pomáhají organizovat běžný text.

CvičeníMinimum V předchozí kapitole jsme zmínili funkci Math.min, která vrací nejmenší ze svých argumentů. Nyní si takovou funkci můžeme napsat sami. Napište funkci min, která vezme dva argumenty a vrátí minimum z nich.

Console.log(min(0, 10)); // → 0 console.log(min(0, -10)); // → -10

Rekurze Viděli jsme, že operátor % (modulo) lze použít k určení, zda je číslo (%2) sudé. Zde je další způsob, jak to definovat:

Nula je sudá.
Jednotka je lichá.
Jakékoli číslo N má stejnou paritu jako N-2.

Napište rekurzivní funkci isDokonce podle těchto pravidel. Musí přijmout číslo a vrátit booleovskou hodnotu.

Otestujte to na 50 a 75. Zkuste to dát -1. Proč se chová tímto způsobem? Je možné to nějak opravit?

Otestujte to na 50 a 75. Podívejte se, jak se chová na -1. Proč? Napadá vás způsob, jak to opravit?

Console.log(isEven(50)); // → true console.log(isEven(75)); // → false console.log(isEven(-1)); // → ??

Počítání fazolí.

Číslo znaku N řetězce lze získat přidáním .charAt(N) („řetězec“.charAt(5)) k němu – podobným způsobem jako při získávání délky řetězce pomocí .length. Vrácenou hodnotou bude řetězec skládající se z jednoho znaku (například „k“). První znak řetězce má pozici 0, což znamená, že poslední znak bude mít pozici string.length – 1. Jinými slovy, řetězec dvou znaků má délku 2 a jeho pozice znaků budou 0 a 1.

Napište funkci countBs, která vezme řetězec jako argument a vrátí počet znaků „B“ obsažených v řetězci.

Pak napište funkci nazvanou countChar, která funguje něco jako countBs, ale vezme si druhý parametr – znak, který budeme v řetězci hledat (místo pouhého počítání počtu znaků „B“). Chcete-li to provést, přepracujte funkci countBs.

Funkce jsou jedním z nejdůležitějších stavebních bloků kódu v JavaScriptu.

Funkce se skládají ze sady příkazů a obvykle jeden provádějí konkrétní úkol(například sčítání čísel, počítání odmocnin atd.).

Kód umístěný ve funkci bude proveden pouze po explicitním volání této funkce.

Deklarace funkce

1. Syntaxe:

//Deklarace funkce functionFunctionname(ln1, ln2)( Kód funkce) //Volání funkceFunctionname(ln1,lr2);

2. Syntaxe:

//Deklarace funkce var function name=function(ln1, ln2)(Kód funkce) //Volání funkce name function(ln1,lr2);

functionname určuje název funkce. Každá funkce na stránce musí mít jedinečný název. Název funkce musí být zadán latinkou a nesmí začínat číslicemi.

ln1 a ln2 jsou proměnné nebo hodnoty, které lze předat funkci. Každé funkci lze předat neomezený počet proměnných.

Upozornění: i když funkci nejsou předány žádné proměnné, nezapomeňte za název funkce vložit závorky "()".

Upozorňujeme, že názvy funkcí v JavaScriptu rozlišují velká a malá písmena.

Příklad funkce JavaScript

Funkce messageWrite() v příkladu níže bude provedena pouze po kliknutí na tlačítko.

Všimněte si, že tento příklad používá událost onclick. Události JavaScriptu bude podrobně probráno dále v této učebnici.

// Funkce zapíše text do funkce stránky messageWrite() ( document.write("Tento text byl na stránku zapsán pomocí JavaScriptu!"); )

Předávání proměnných funkcím

Do funkcí můžete předat neomezený počet proměnných.

Upozornění: veškeré manipulace s proměnnými uvnitř funkcí se ve skutečnosti neprovádějí na proměnných samotných, ale na jejich kopii, takže obsahy samotných proměnných se v důsledku provádění funkcí nemění.

/* Definujme funkci, která přidá 10 k předané proměnné a zobrazí výsledek na stránce */ function plus(a)( a=a+10; document.write("Výstup funkce: " + a+"
"); ) var a=25; document.write("Hodnota proměnné před voláním funkce: "+a+"
"); // Volání funkce předáním proměnné a plus(a); document.write("Hodnota proměnné po volání funkce: "+a+"
");

Rychlý pohled

Chcete-li přistupovat ke globální proměnné z funkce spíše než z její kopie, použijte window.variable_name.

Funkce plus(a)( window.a=a+10; ) var a=25; document.write("Hodnota proměnné před voláním funkce: "+a+"
"); plus(a); document.write("Hodnota proměnné po volání funkce: "+a+"
");

Rychlý pohled

návratový příkaz

Pomocí příkazu return můžete vrátit hodnoty z funkcí.

//Funkce sum vrací součet proměnných, které jí byly předány function sum(v1,v2)( return v1+v2; ) document.write("5+6=" + sum(5,6) + "
"); document.write("10+4=" + suma(10,4) + "
");

Rychlý pohled

Vestavěné funkce

Kromě uživatelsky definovaných funkcí má JavaScript také vestavěné funkce.

Například vestavěná funkce isFinite umožňuje zkontrolovat, zda je předaná hodnota platné číslo.

Document.write(isFinite(40)+"
"); document.write(isFinite(-590)+"
"); document.write(isFinite(90,33)+"
"); document.write(isFinite(NaN)+"
"); document.write(isFinite("Toto je řetězec")+"
");

Rychlý pohled

Poznámka: úplný seznam vestavěný Funkce JavaScriptu Najdete ho v našem.

Lokální a globální proměnné

Proměnné vytvořené uvnitř funkcí se nazývají lokální proměnné. K takovým proměnným máte přístup pouze v rámci funkcí, ve kterých byly definovány.

Po dokončení provádění kódu funkce jsou takové proměnné zničeny. To znamená, že proměnné se stejným názvem mohou být definovány v různých funkcích.

Proměnné, které jsou vytvořeny mimo funkční kód, se nazývají globální proměnné; k takovým proměnným lze přistupovat odkudkoli v kódu.

Pokud deklarujete proměnnou bez var uvnitř funkce, stane se také globální.

Globální proměnné jsou zničeny až po zavření stránky.

//Deklarování globálních proměnných var1 a var2 var var1="var1 existuje"; var var2; function func1() ( //Přiřadit var2 hodnotu uvnitř funkce func1 var var2="var2 existuje"; ) //Z jiné funkce vypíše obsah proměnné var1 a var2 do funkce stránky func2() ( //Output obsah proměnné var1 document.write( var1 + "
"); //Vypíše obsah proměnné var2 document.write(var2); )

Rychlý pohled

Všimněte si, že při tisku na obrazovku bude mít var2 prázdnou hodnotu, protože funkce func1 funguje na místní "verzi" var2.

Použití anonymních funkcí

Funkce, které při deklaraci neobsahují název, se nazývají anonymní.

Anonymní funkce jsou v zásadě deklarovány tak, aby nebyly následně volány z kódu jako běžné funkce, ale aby byly předány jiným funkcím jako parametr.

Funkce arrMap(arr,func)( var res=nové pole; for (var i=0;i