Počítače Okna Internet

Deklarování funkce v sekci deklarace. Struktura programu. Výrazy a operátory v JavaScriptu

Ahoj všichni! V tomto článku chci mluvit o čem jako je deklarace funkce a výraz funkce v programovacím jazyce JavaScript.

Na webu už byl článek o tom, co je funkce, jak ji vytvořit a používat. Pokud jste ji ještě nečetli, můžete si ji přečíst

O tom se mluvilo v článku deklarace funkce.

Pokud se chcete zeptat funkční výraz, pak musíte napsat takto:

Var func = funkce(a, b) ( return a + b; );

Tito. proměnné přiřadíme funkci. Vezměte prosím na vědomí, že na konci je středník a to je nutné udělat vždy, protože toto je pouze hodnota proměnné in deklarace funkce Není potřeba používat středníky. Ve skutečnosti, pokud středník nevložíte, pak se s největší pravděpodobností nestane nic špatného, ​​ale existují situace, kdy to z vás může udělat krutý vtip a pak bude docela obtížné tuto chybu najít.

Nyní si promluvme o rozdílech mezi těmito dvěma deklaracemi funkcí.

Deklarace funkce

součet();

Funkce sum() (
alert("Fungovalo to!");
}

Takže pokud jste si mysleli, tady je správná odpověď: ANO, bude pracovat.

Jak je tohle možné?

Odpověď je velmi jednoduchá. Faktem je, že před spuštěním kódu jej interpret projde a shromáždí všechny deklarace proměnných a funkcí na speciálním místě. Ukáže se, že on, interpret, již zná celý zdrojový kód funkce a může ji volat, i když je v kódu napsána níže.

Funkční výraz

Všechno je zde přesně naopak.

Var func = function() (
alert("Fungovalo to!");
};

Interpret se o takových funkcích dozví, až když na ně přijde v kódu, takže výše uvedený příklad nebude fungovat. Pokud však níže napíšete volání funkce, pak bude vše fungovat.

Proč potřebujeme výraz funkce?

Ve skutečnosti se používají na mnoha místech, ale uvedu zde extrémně banální příklad.

If(věk >= 18) (
var func = function() (
alert("Vítejte!");
};
) jinak (
var func = function() (
alert("Na tebe je ještě příliš brzy!");
};
}

Nyní, v závislosti na podmínkách, do proměnné func bude napsán jiný zdrojový kód, a proto se funkce budou chovat odlišně.

S deklarace funkce takový trik nebude fungovat.

If(věk >= 18) (
funkce function() (
alert("Vítejte!");
}
) jinak (
funkce function() (
alert("Na tebe je ještě příliš brzy!");
}
}

Zde je pro vás další problém. Přemýšlejte o tom, co výše uvedený kód udělá a co upozornění(která funkce) bude nakonec fungovat.

Interpret se podívá na kód shora dolů, proto zapíše hodnotu poslední funkce a zavolá ji.

Doufám tedy, že chápete rozdíly mezi těmito 2 deklaracemi funkcí.

The funkce klíčové slovo lze použít k definování funkce uvnitř výrazu.

Zdroj pro tento interaktivní příklad je uložen v úložišti GitHub. Pokud byste chtěli přispět k projektu interaktivních příkladů, naklonujte prosím https://github.com/mdn/interactive-examples a zašlete nám žádost o stažení.

Syntax

var myFunction = funkce [ název]([param1[, param2[, ..., paramN]]]) { prohlášení };

Parametry

name Název funkce. Lze vynechat, v takovém případě je funkce anonymní. Název je pouze lokální pro tělo funkce. paramN Název argumentu, který má být předán funkci. příkazy Příkazy, které tvoří tělo funkce.

Popis

Výraz funkce je velmi podobný a má téměř stejnou syntaxi jako příkaz funkce (podrobnosti viz příkaz funkce). Hlavní rozdíl mezi výrazem funkce a příkazem funkce je název funkce které lze ve výrazech funkcí vynechat a vytvořit anonymní funkcí. Funkční výraz lze použít jako IIFE (Immediately Invoked Function Expression), který se spustí, jakmile je definován. Další informace naleznete také v kapitole o funkcích.

Funkce exprese zvedání

Funkční výrazy v JavaScriptu nejsou na rozdíl od deklarací funkcí zvednuty. Nemůžete použít funkční výrazy, než je definujete:

Console.log(notHoisted) // nedefinováno //i když je název proměnné zvednutý, definice není, takže je nedefinovaná. notHoisted(); // TypeError: notHoisted není funkce var notHoisted = function() ( console.log("bar"); );

Výraz pojmenované funkce

Pokud chcete odkazovat na aktuální funkci v těle funkce, musíte vytvořit výraz pojmenované funkce. Tento název je pak lokální pouze pro tělo funkce (rozsah) . Tím se také vyhnete použití nestandardní vlastnosti arguments.callee.

Var math = ( "factit": function factorial(n) ( console.log(n) if (n<= 1) { return 1; } return n * factorial(n - 1); } }; math.factit(3) //3;2;1;

Proměnná, ke které je funkční výraz přiřazen, bude mít vlastnost name. Název se nezmění, pokud je přiřazen k jiné proměnné. Pokud je název funkce vynechán, bude to název proměnné (implicitní název). Pokud je přítomen název funkce, bude to název funkce (explicitní název). To platí také pro funkce šipek (šipky nemají název, takže proměnné můžete dát pouze implicitní název).

Var foo = function() () foo.name // "foo" var foo2 = foo foo2.name // "foo" var bar = funkce baz() () bar.name // "baz" console.log(foo === foo2); // true console.log(typeof baz); // nedefinováno console.log(bar === baz); // false (chyby, protože baz == nedefinováno)

Příklady

Následující příklad definuje nepojmenovanou funkci a přiřadí ji x . Funkce vrátí druhou mocninu svého argumentu:

Var x = funkce(y) ( return y * y; ); button.addEventListener("click", function(event) ( console.log("tlačítko je kliknuto!") ))

Specifikace

Specifikace Postavení Komentář
ECMAScript nejnovější koncept (ECMA-262)
Návrh
ECMAScript 2015 (6. vydání, ECMA-262)
Definice "definice funkcí" v této specifikaci.
Standard
ECMAScript 5.1 (ECMA-262)
Standard
ECMAScript 3rd Edition (ECMA-262)
Definice "definice funkce" v této specifikaci.
Standard Počáteční definice. Implementováno v JavaScriptu 1.5.

Kompatibilita s prohlížečem

Tabulka kompatibility na této stránce je generována ze strukturovaných dat. Pokud byste chtěli přispět k datům, podívejte se na https://github.com/mdn/browser-compat-data a pošlete nám žádost o stažení.

Aktualizujte údaje o kompatibilitě na GitHubu

plocha počítačemobilní, pohyblivíServer
ChromeOkrajFirefoxinternet ExplorerOperaSafariWebové zobrazení AndroidChrome pro AndroidFirefox pro AndroidOpera pro AndroidSafari na iOSInternet SamsungNode.js
funkcePlná podpora Chrome AnoPlná podpora Edge 12Plná podpora Firefoxu 1IE Plná podpora AnoOpera Plná podpora AnoSafari Plná podpora AnoWebView Plná podpora Androidu AnoChrome Plná podpora Androidu AnoFirefox Plná podpora Androidu 4Opera Android Plná podpora AnoSafari iOS Plná podpora AnoSamsung Internet Android Plná podpora Anonodejs Plná podpora Ano
Koncová čárka v parametrechPlná podpora Chrome 58Edge No support NoPlná podpora Firefoxu 52IE Žádná podpora NeOpera plná podpora 45Safari Žádná podpora NeWebView Plná podpora Androidu 58Chrome Plná podpora Androidu 58Firefox Plná podpora Androidu 52Opera Android Plná podpora 43Safari iOS Žádná podpora NeSamsung Internet Android Plná podpora 7.0nodejs Plná podpora 8.0.0

Legenda

Plná podpora Plná podpora Bez podpory Bez podpory

Jako objekt jazyka C musí být funkce deklarována. Deklarování uživatelské funkce, tzn. jeho deklarace se provádí ve dvou formách - ve formě popisu a ve formě definice.

Popis funkce spočívá v tom, že nejprve představíte programový soubor jejího prototypu. Prototyp funkce informuje kompilátor, že jeho úplná definice (jeho plný text) bude uvedena později v textu programu: v aktuálním nebo jiném zdrojovém souboru nebo umístěná v knihovně.

Jazyková norma používá následující metodu deklarace funkcí:

typ_výsledku ID _funkce(typ proměnné1, ..., typ proměnné N);

Všimněte si, že není nutné uvádět identifikátory proměnných v závorkách prototypu, protože jazykový kompilátor je nezpracovává.

Popis prototypu umožňuje kompilátoru zkontrolovat, zda se typy a počet parametrů shodují, když je funkce skutečně volána.

Příklad zábavného popisu funkce se seznamem parametrů:

float fun(int, float, int, int);

Kompletní definice funkce je následující:

typ_výsledku ID _functions (seznam parametrů)

funkční kód

Typ výsledku určuje typ výrazu, jehož hodnota je vrácena do bodu jeho volání pomocí operátoru vrátit se<выражение> .

Pokud typ funkce není zadán, předpokládá se výchozí typ int .

Seznam parametrů se skládá ze seznamu typů parametrů a identifikátorů parametrů oddělených čárkami.

Funkce nemusí mít parametry, ale závorky jsou v každém případě povinné.

Pokud funkce nevrací žádnou hodnotu, musí být deklarována jako funkce typu prázdnota (prázdný).

V tomto případě operátor vrátit se nemusíš to dávat.

Funkce může mít více příkazů vrátit se , ale nemusí tam být žádné. V takových případech dojde k návratu k volajícímu programu po provedení posledního příkazu ve funkci.

Příklad funkce, která určuje nejmenší hodnotu dvou celočíselných proměnných:

int min (int x, int y)

návrat (x

Všechny funkce, které vracejí hodnotu, musí být použity na pravé straně výrazů C, jinak bude vrácený výsledek ztracen.

Pokud funkce nemá seznam parametrů, je vhodné při deklaraci takové funkce uvést v závorce i klíčové slovo void. Například, void main (void).

Výrazy v JavaScriptu jsou kombinace operandy A operátory.

Operace ve výrazech se provádějí postupně podle hodnoty priority (čím vyšší je hodnota priority, tím je vyšší). Vrácený výsledek není vždy stejného typu jako typ zpracovávaných dat. Například operace porovnání zahrnují operandy různých typů, ale výsledkem bude vždy booleovský typ.

Rýže. 1. Struktura výrazů v JavaScriptu

Operandy jsou data zpracovaná skriptem JavaScript. Operandy mohou být jednoduché nebo složité datové typy, stejně jako další výrazy.

Operátoři jsou jazykové symboly, které provádějí různé operace s daty. Operátory lze psát pomocí interpunkčních znaků nebo klíčových slov.

V závislosti na počtu operandů se rozlišují následující typy operátorů:
unární— jeden operand je zapojen do operace;
binární— operace zahrnuje dva operandy;
trojice— kombinuje tři operandy.

Nejjednodušší forma vyjádření je doslovný— něco, co se samo hodnotí, například číslo 100, řetězec „Ahoj světe“ . Proměnná může být také výraz, protože se vyhodnocuje na hodnotu, která je jí přiřazena.

Výrazy a operátory v JavaScriptu

1. Aritmetické operátory

Aritmetické operátory jsou navrženy k provádění matematických operací, pracují s číselnými operandy (nebo proměnnými, které ukládají číselné hodnoty), a jako výsledek vracejí číselnou hodnotu.

Pokud je jedním z operandů řetězec, interpret JavaScriptu se jej pokusí převést na číselný typ a poté provede příslušnou operaci. Pokud převod typu není možný, výsledkem bude NaN (nikoli číslo).

Tabulka 1. Aritmetické operátory
Operátor/Provoz Popis Priorita
+ Dodatek Přidá číselné operandy. Pokud je jedním z operandů řetězec, pak výsledkem výrazu je řetězec. 12
- Odečítání Odečte druhý operand od prvního. 12
- Unární mínus Převede kladné číslo na záporné a naopak. 14
* Násobení Vynásobí dva operandy. 13
/ Divize Vydělí první operand druhým. Výsledkem dělení může být celé číslo nebo číslo s plovoucí desetinnou čárkou. 13
% Modulo dělení (zbytek divize) Vypočítá zbytek vyplývající z celočíselného dělení prvního operandu druhým. Platí pro celá čísla i čísla s plovoucí desetinnou čárkou. 13
var x = 5, y = 8, z; z = x + y; // návrat 13 z = x - y; // návrat -3 z = - y; // návrat -8 z = x * y; // návrat 40 z = x / y; // návrat 0,625 z = y % x; // návrat 3

2. Operátoři přiřazení

Operátoři přiřazení se používají k přiřazení hodnot proměnným. Kombinované operátory umožňují uložit původní a následné hodnoty do jedné proměnné.

var a = 5; // přiřadí číselnou hodnotu 5 proměnné a var b = "hello"; // ulož řetězec hellow do proměnné b var m = n = z = 10; // přiřadíme proměnným m, n, z číselnou hodnotu 10 x += 10; // ekvivalentní x = x + 10; x = 10; // ekvivalentní x = x - 10; x*= 10; // ekvivalentní x = x * 10; x/= 10; // ekvivalentní x = x / 10; x %= 10; // ekvivalentní x = x % 10;

3. Operátory inkrementace a dekrementace

Operace zvýšení a snížení jsou unární a zvyšují a snižují hodnotu operandu o jedna. Operandem může být proměnná, prvek pole nebo vlastnost objektu. Nejčastěji se takové operace používají ke zvýšení čítače ve smyčce.

var x = y = m = n = 5, z, s, k, l; z = ++x* 2; /* jako výsledek výpočtů vrátí hodnotu z = 12, x = 6, tzn. hodnota x se nejprve zvýší o 1 a poté se provede operace násobení */ s = y++ * 2; /* jako výsledek výpočtů vrátí hodnotu s = 10, y = 6, tzn. Nejprve se provede operace násobení a poté se hodnota zvýšená o 1 uloží do proměnné y */ k = --m * 2; // vrátí hodnotu k = 8, m = 4 l = n-- * 2; // vrátí hodnotu l = 10, n = 4

4. Porovnávací operátory

Porovnávací operátory se používají ke shodě operandů, výsledkem výrazu může být jedna ze dvou hodnot - true nebo false . Operandy mohou být nejen čísla, ale také řetězce, logické hodnoty a objekty. Porovnání však lze provádět pouze na číslech a řetězcích, takže se převedou operandy, které nejsou čísly nebo řetězci.

Pokud oba operandy nelze úspěšně převést na čísla nebo řetězce, operátory vždy vrátí false .

Pokud jsou oba operandy řetězce/čísla nebo je lze převést na řetězce/čísla, budou porovnány jako řetězce/čísla.

Pokud je jeden operand řetězec/převádí se na řetězec a druhý je číslo/převádí se na číslo, operátor se pokusí převést řetězec na číslo a provést porovnání čísel. Pokud řetězec není číslo, převede se na NaN a výsledek porovnání je false .

Nejčastěji se srovnávací operace používají při organizování poboček v programech.

Tabulka 4. Porovnávací operátory
Operátor/Provoz Popis Priorita
== Rovnost Testuje dvě hodnoty na stejnou hodnotu, což umožňuje převod typu. Vrátí hodnotu true, pokud jsou operandy stejné, a hodnotu false, pokud jsou různé. 9
!= Nerovnost Vrátí hodnotu true, pokud se operandy nerovnají 9
=== Identita Testuje dva operandy na "identitu" pomocí přesné definice shody. Vrátí hodnotu true, pokud jsou operandy stejné bez konverze typu. 9
!== Netotožnost Provádí ověření identity. Vrátí hodnotu true, pokud operandy nejsou stejné bez konverze typu. 9
> Více Vrátí hodnotu true, pokud je první operand větší než druhý, jinak vrátí hodnotu false. 10
>= Větší nebo rovno Vrátí hodnotu true, pokud první operand není menší než druhý, jinak vrátí hodnotu false. 10
Vrátí hodnotu true, pokud je první operand menší než druhý, jinak vrátí hodnotu false. 10
Vrátí hodnotu true, pokud první operand není větší než druhý, jinak vrátí hodnotu false. 10
5 == "5"; // návrat true 5 != -5.0; // návrat true 5 === "5"; // návrat false false === false; // návrat true 1 !== true; // návrat true 1 != true; // vrátí false, protože true je převedeno na 1 3 > -3; // návrat true 3 >= "4"; // vrátí false

5. Logické operátory

Logické operátory umožňují kombinovat podmínky, které vracejí booleovské hodnoty. Nejčastěji se používá v podmíněném příkazu if.

(2 < 3) && (3===3); // вернет true, так как выражения в обеих скобках дают true (x < 10 && x >0); // vrátí true, pokud je x v rozsahu od 0 do 10 !false; // vrátí true

6. Bitové operátory

Bitové operátory pracovat s operandy jako 32bitovou sekvencí jedniček a nul a vracet číselnou hodnotu označující výsledek operace zapsanou v desítkové soustavě. Celá čísla jsou považována za operandy, zlomková část operandu se zahodí. Bitové operace lze využít například při šifrování dat, práci s příznaky a vymezování přístupových práv.

Tabulka 6. Bitové operátory
Operátor/Provoz Popis Priorita
& Bitově AND Pokud jsou oba bity 1, bude výsledný bit 1. Jinak je výsledek 0. 8
| Bitově NEBO Pokud jeden z operandů obsahuje 1 na pozici, bude výsledek obsahovat také 1 na této pozici, jinak bude výsledek na této pozici 0. 6
^ Exkluzivní NEBO Pokud jedna a pouze jedna hodnota obsahuje na libovolné pozici 1, bude výsledek obsahovat na této pozici 1, jinak bude výsledek na této pozici 0. 7
~ Popírání Na binární reprezentaci hodnoty výrazu se provede bitová negační operace. Jakákoli pozice obsahující 1 v původním výrazu je nahrazena 0. Jakákoli pozice obsahující 0 v původním výrazu se stane 0 . Kladná čísla začínají na 0, záporná čísla začínají na -1, takže ~ n == -(n+1) . 14
Operátor posouvá bity prvního operandu doleva o počet bitových pozic nastavených druhým operandem. Nuly se používají k vyplnění pozic vpravo. Vrátí výsledek stejného typu jako levý operand. 11
>> Bitový posun doprava Operátor posouvá bity prvního operandu doprava o počet bitových pozic nastavených druhým operandem. Číslice posunuté mimo rozsah jsou odstraněny. Nejvýznamnější bit (32.) je ponechán beze změny, aby se zachovalo znaménko výsledku. Pokud je první operand kladný, jsou nejvýznamnější bity výsledku vyplněny nulami; pokud je první operand záporný, jsou nejvýznamnější bity výsledku vyplněny jedničkami. Posunutí hodnoty doprava o jednu pozici je ekvivalentní dělení 2 (zahození zbytku) a posunutí doprava o dvě pozice je ekvivalentní dělení 4 atd. 11
>>> Bitový posun doprava bez znaménka Operátor posouvá bity prvního operandu doprava o počet bitových pozic nastavených druhým operandem. Nuly se přidávají vlevo, bez ohledu na znaménko prvního operandu. Číslice posunuté mimo rozsah jsou odstraněny. 11
var x = 9, y = 5, z = 2, s = -5, výsledek; // 9 je ekvivalentní 1001, 5 je ekvivalentní 0101 výsledek = x & y; // vrátí 1 (ekvivalent 0001) výsledek = x | y; // vrátí 13 (ekvivalent 1101) vysledek = x ^ y; // vrátí 12 (ekvivalent 1100) vysledek = ~ y; // vrátí -6 (ekvivalent 1100) výsledek = x<< y; // вернет 288 (эквивалентно 100100000) result = x >> z; // návrat 2 (ekvivalent 10) vysledek = s >>> z; // vrátí 1073741822 (ekvivalent 11111111111111111111111111110)

7. Řetězcové operátory

Existuje několik operátorů, které pracují s řetězci speciálními způsoby.

"1" + "10"; // návrat "110" "1" + 10; // vrátí "110" 2 + 5 + "barevné tužky"; // vrátí "7 barevných tužek" "Barevné tužky" + 2 + 5; // vrátí "25 barevných tužek" "1" > "10"; // vrátí false "10"<= 10; // вернет true "СССР" == "ссср"; // вернет false x = "micro"; x+= "soft"; // вернет "microsoft"

8. Speciální operátory

Tabulka 8. Speciální operátory
Operátor/Provoz Popis Priorita
. Přístup k nemovitosti Přistupuje k vlastnosti objektu. 15
,Vícenásobný výpočet Vyhodnocuje více nezávislých výrazů napsaných na jednom řádku. 1
Indexování pole Přistupuje k prvkům pole nebo vlastnostem objektu. 15
() Volání funkce, seskupování Seskupuje operace nebo volá funkci. 15
typeof Definice datového typu Unární operátor, vrací datový typ operandu. 14
instanceof Kontrola typu objektu Operátor kontroluje, zda je objekt instancí určité třídy. Levý operand musí být objekt, pravý operand musí obsahovat název třídy objektu. Výsledek bude pravdivý, pokud je objekt nalevo instancí třídy napravo, jinak bude nepravda. 10
v Kontrola přítomnosti nemovitosti Levý operand musí být řetězec a pravý operand musí být pole nebo objekt. Pokud je levá hodnota vlastností objektu, výsledek bude true . 10
nový Vytvoření objektu Operátor vytvoří nový objekt s nedefinovanými vlastnostmi, poté zavolá funkci konstruktoru, aby jej inicializoval (předání parametrů). Lze také použít k vytvoření pole. 1
smazat Vymazat Operátor umožňuje odstranit vlastnost z objektu nebo prvku z pole. Vrací hodnotu true, pokud bylo odstranění úspěšné, v opačném případě vrací hodnotu false. Když je prvek pole odstraněn, jeho délka se nezmění. 14
void Definování výrazu bez návratové hodnoty Unární operátor, zahodí hodnotu operandu a vrátí underfined . 14
?: Operátor podmíněného výrazu Ternární operátor umožňuje organizovat jednoduché větvení. Výraz obsahuje tři operandy, první musí být booleovská hodnota nebo musí být převedena na jednu a druhý a třetí musí být libovolné hodnoty. Pokud má první operand hodnotu true , pak podmíněný výraz převezme hodnotu druhého operandu; pokud nepravda - pak třetí. 3
document.write("ahoj světe"); // zobrazí řetězec hello world i = 0, j = 1; // ukládá hodnoty do proměnných function1(10, 5); // volání funkce function1 s parametry 10 a 5 var year = ; // vytvoří pole s prvky typeof (a:1); // return "object" var d = new Date(); // vytvoření nového objektu pomocí konstruktoru Date() d instanceof Date; // return true var mycar = (make: "Honda", model: "Accord", rok: 2005); "vyrobit" v mycaru; // return true var obj = new Object(); // vytvoří prázdný objekt var food = ["mléko", "chléb", "maso", "olivový olej", "sýr"]; odstranit jídlo; // odebere čtvrtý prvek z pole food x > 10 ? x*2: x/2; // vrátí x * 2, pokud x > 10, jinak x / 2

9. Komentáře v JavaScriptu

Jednořádkový komentář: před text komentáře musí být uvedeny symboly // .

Funkce jsou jedním ze základních stavebních kamenů JavaScriptu. Funkce je procedura JavaScriptu – sada příkazů, která provádí úlohu nebo vypočítává hodnotu. Chcete-li použít funkci, musíte ji definovat někde v rozsahu, ze kterého ji chcete volat.

A metoda je funkce, která je vlastností objektu. Přečtěte si více o objektech a metodách v části Práce s objekty.

Volání funkcí

Definování funkce ji neprovede. Definování funkce jednoduše pojmenuje funkci a určí, co se má dělat, když je funkce volána. Povolání funkce skutečně provádí zadané akce s uvedenými parametry. Pokud například definujete funkci square , můžete ji nazvat takto:

Čtverec(5);

Předchozí příkaz volá funkci s argumentem 5. Funkce provede své příkazy a vrátí hodnotu 25.

Funkce musí být v rozsahu, když jsou volány, ale deklaraci funkce lze zvednout (objeví se pod voláním v kódu), jako v tomto příkladu:

Console.log(čtverec(5)); /* ... */ function square(n) ( return n * n; )

Rozsah funkce je funkce, ve které je deklarována, nebo celý program, pokud je deklarován na nejvyšší úrovni.

Poznámka: To funguje pouze při definování funkce pomocí výše uvedené syntaxe (tj. funkce funcName()()). Níže uvedený kód nebude fungovat. To znamená, že funkce zvedání funguje pouze s deklarací funkce a ne s výrazem funkce.

Console.log(čtverec); // čtverec je zvednut s počáteční hodnotou nedefinovanou. console.log(čtverec(5)); // Uncaught TypeError: square není funkce var square = function(n) ( return n * n; )

Argumenty funkce nejsou omezeny na řetězce a čísla. Funkci můžete předat celé objekty. Funkce show_props() (definovaná v ) je příkladem funkce, která přebírá objekt jako argument.

Funkce může volat sama sebe. Zde je například funkce, která rekurzivně počítá faktoriály:

Funkce faktoriál(n) ( if ((n === 0) || (n === 1)) návrat 1; jinak návrat (n * faktoriál(n - 1)); )

Potom byste mohli vypočítat faktoriály jedna až pět takto:

Var a, b, c, d, e; a = faktoriál(1); // a získá hodnotu 1 b = faktoriál(2); // b získá hodnotu 2 c = faktoriál(3); // c získá hodnotu 6 d = faktoriál(4); // d dostane hodnotu 24 e = faktoriál(5); //e získá hodnotu 120

Existují i ​​jiné způsoby volání funkcí. Často existují případy, kdy je třeba funkci volat dynamicky nebo se počet argumentů funkce liší, nebo kdy je třeba kontext volání funkce nastavit na konkrétní objekt určený za běhu. Ukazuje se, že funkce jsou samy o sobě objekty a tyto objekty zase mají metody (viz objekt Function). K dosažení tohoto cíle lze použít jednu z nich, metodu apply().

Rozsah funkcí

K proměnným definovaným uvnitř funkce nelze přistupovat odkudkoli mimo funkci, protože proměnná je definována pouze v rozsahu funkce. Funkce však může přistupovat ke všem proměnným a funkcím definovaným v rozsahu, ve kterém je definována. Jinými slovy, funkce definovaná v globálním rozsahu může přistupovat ke všem proměnným definovaným v globálním rozsahu. Funkce definovaná uvnitř jiné funkce může také přistupovat ke všem proměnným definovaným v její rodičovské funkci a jakékoli jiné proměnné, ke které má rodičovská funkce přístup.

// Následující proměnné jsou definovány v globálním rozsahu var num1 = 20, num2 = 3, name = "Chamahk"; // Tato funkce je definována ve funkci globálního rozsahu multiply() ( return num1 * num2; ) multiply(); // Vrátí 60 // Příklad vnořené funkce funkce getScore() ( var num1 = 2, num2 = 3; funkce add() ( návratový název + " skóre " + (num1 + num2); ) return add(); ) getScore (); // Vrátí "Chamahk skóroval 5"

Rozsah a zásobník funkcí

Rekurze

Funkce může odkazovat a volat sama sebe. Funkce se může odkazovat na sebe třemi způsoby:

  1. název funkce
  2. proměnná v rozsahu, která odkazuje na funkci

Zvažte například následující definici funkce:

Var foo = function bar() ( // příkazy jdou sem );

V těle funkce jsou všechny následující ekvivalenty:

  1. bar()
  2. arguments.callee()
  3. foo()

Funkce, která volá sama sebe, se nazývá a rekurzivní funkce. V některých ohledech je rekurze analogická smyčce. Oba spouštějí stejný kód vícekrát a oba vyžadují podmínku (aby se zabránilo nekonečné smyčce, nebo v tomto případě spíše nekonečné rekurzi). Například následující smyčka:

Var x = 0; zatímco (x< 10) { // "x < 10" is the loop condition // do stuff x++; }

lze převést na rekurzivní funkci a volání této funkce:

Funkční smyčka(x) ( if (x >= 10) // "x >= 10" je výstupní podmínka (ekvivalentní "!(x< 10)") return; // do stuff loop(x + 1); // the recursive call } loop(0);

Některé algoritmy však nemohou být jednoduchými iteračními smyčkami. Například získání všech uzlů stromové struktury (např. DOM) se snadněji provede pomocí rekurze:

Funkce walkTree(node) ( if (node ​​​​== null) // návrat; // udělejte něco s uzlem pro (var i = 0; i< node.childNodes.length; i++) { walkTree(node.childNodes[i]); } }

Ve srovnání s funkční smyčkou zde každé rekurzivní volání samo o sobě provádí mnoho rekurzivních volání.

Je možné převést jakýkoli rekurzivní algoritmus na nerekurzivní, ale často je logika mnohem složitější a vyžaduje použití zásobníku. Ve skutečnosti samotná rekurze používá zásobník: zásobník funkcí.

Chování podobné zásobníku lze vidět v následujícím příkladu:

Funkce foo(i) (pokud (i< 0) return; console.log("begin: " + i); foo(i - 1); console.log("end: " + i); } foo(3); // Output: // begin: 3 // begin: 2 // begin: 1 // begin: 0 // end: 0 // end: 1 // end: 2 // end: 3

Vnořené funkce a uzávěry

Funkci můžete vnořit do funkce. Vnořená (vnitřní) funkce je soukromá pro její obsahující (vnější) funkci. Tvoří také a uzavření. Uzávěr je výraz (obvykle funkce), který může mít volné proměnné spolu s prostředím, které tyto proměnné váže (které výraz „uzavře“).

Protože vnořená funkce je uzávěr, znamená to, že vnořená funkce může „zdědit“ argumenty a proměnné své obsahující funkce. Jinými slovy, vnitřní funkce obsahuje rozsah vnější funkce.

  • Vnitřní funkce je přístupná pouze z příkazů ve vnější funkci.
  • Vnitřní funkce tvoří uzávěr: vnitřní funkce může používat argumenty a proměnné vnější funkce, zatímco vnější funkce nemůže používat argumenty a proměnné vnitřní funkce.

Následující příklad ukazuje vnořené funkce:

Funkce addSquares(a, b) ( function square(x) ( return x * x; ) return square(a) + square(b); ) a = addSquares(2, 3); // vrátí 13 b = addSquares(3, 4); // vrátí 25 c = addSquares(4, 5); // vrátí 41

Protože vnitřní funkce tvoří uzávěr, můžete volat vnější funkci a zadat argumenty pro vnější i vnitřní funkci:

Funkce vně (x) ( funkce inside(y) ( return x + y; ) return inside; ) fn_inside = outside(3); // Přemýšlejte o tom jako: dejte mi funkci, která přidá 3 ke všemu, co dáte // it result = fn_inside(5); // vrátí 8 vysledek1 = mimo(3)(5); // vrátí 8

Zachování proměnných

Všimněte si, jak je x zachováno, když je vráceno dovnitř. Uzavření musí zachovat argumenty a proměnné ve všech oblastech, na které odkazuje. Vzhledem k tomu, že každé volání poskytuje potenciálně odlišné argumenty, vytvoří se pro každé volání mimo . Paměť lze uvolnit pouze tehdy, když vrácený vnitřek již není přístupný.

To se neliší od ukládání referencí do jiných objektů, ale často je to méně zřejmé, protože reference nenastavujeme přímo a nelze je kontrolovat.

Vícenásobně vnořené funkce

Funkce mohou být vícenásobně vnořené, tzn. funkce (A) obsahující funkci (B) obsahující funkci (C). Obě funkce B a C zde tvoří uzávěry, takže B má přístup k A a C má přístup k B. Navíc, protože C má přístup k B, které má přístup k A, C může také přistupovat k A. Uzávěry tedy mohou obsahovat více rozsahů; rekurzivně obsahují rozsah funkcí, které je obsahují. Tomu se říká řetězení rozsahu. (Proč se tomu říká „řetězení“ bude vysvětleno později.)

Zvažte následující příklad:

Funkce A(x) ( funkce B(y) ( funkce C(z) ( console.log(x + y + z); ) C(3); ) B(2); ) A(1); // protokoly 6 (1 + 2 + 3)

V tomto příkladu C přistupuje k B "s y a A "s x . To lze provést, protože:

  1. B tvoří uzávěr obsahující A, tzn. B má přístup k argumentům a proměnným A.
  2. C tvoří uzávěr včetně B.
  3. Protože uzávěr B zahrnuje A, uzávěr C zahrnuje A, C má přístup k oběma B a Argumenty a proměnné A. Jinými slovy, C řetězy rozsahy B a A v tomto pořadí.

Opak však není pravdou. A nemůže přistupovat k C , protože A nemá přístup k žádnému argumentu nebo proměnné B , což je C proměnná. C tedy zůstává soukromý pouze pro B .

Konflikty jmen

Když dva argumenty nebo proměnné v rozsahu uzávěru mají stejný název, existuje a konflikt jmen. Více vnitřních rozsahů má přednost, takže nejvnitřnější rozsah má nejvyšší prioritu, zatímco vnější rozsah má nejnižší. Toto je rozsahový řetězec. První na řetězu je nejvnitřnější dalekohled a poslední je nejvzdálenější. Zvažte následující:

Funkce outside() ( var x = 5; funkce inside(x) ( return x * 2; ) return inside; ) outside())(10); // vrátí 20 místo 10

Ke konfliktu názvů dochází při příkazu return x a nachází se mezi uvnitř "s parametrem x a vně "s proměnnou x. Řetězec rozsahu je zde ( inside , outside , global object). Proto uvnitř "s x má přednost před vnějším "s x" a vrátí se 20 (uvnitř "s x) místo 10 (mimo "s x).

Uzávěry

Uzávěry jsou jednou z nejvýkonnějších funkcí JavaScriptu. JavaScript umožňuje vnořování funkcí a poskytuje vnitřní funkci plný přístup ke všem proměnným a funkcím definovaným uvnitř vnější funkce (a všem ostatním proměnným a funkcím, ke kterým má vnější funkce přístup). Vnější funkce však nemá přístup k proměnným a funkcím definovaným uvnitř vnitřní funkce. To poskytuje jakési zapouzdření proměnných vnitřní funkce. Jelikož má vnitřní funkce přístup k rozsahu vnější funkce, proměnné a funkce definované ve vnější funkci budou žít déle, než je doba provádění vnější funkce, pokud se vnitřní funkci podaří přežít po dobu životnosti vnější funkce. funkce. Uzávěr se vytvoří, když je vnitřní funkce nějakým způsobem zpřístupněna libovolnému rozsahu mimo vnější funkci.

Var pet = function(name) ( // Vnější funkce definuje proměnnou s názvem "name" var getName = function() ( return name; // Vnitřní funkce má přístup k proměnné "name" vnější //function ) return getName; // Vrátí vnitřní funkci, čímž ji vystaví vnějším rozsahům ) myPet = pet("Vivie"); můj mazlíček(); // Vrátí "Vivie"

Může být mnohem složitější než výše uvedený kód. Lze vrátit objekt obsahující metody pro manipulaci s vnitřními proměnnými vnější funkce.

Var createPet = function(name) ( var sex; return ( setName: function(newName) ( name = newName; ), getName: function() ( return name; ), getSex: function() ( return sex; ), setSex: function(newSex) ( if(typeof newSex === "string" && (newSex.toLowerCase() === "male" || newSex.toLowerCase() === "female")) ( sex = newSex; ) ) ) ) var pet = createPet("Vivie"); pet.getName(); // Vivie pet.setName("Oliver"); pet.setSex("muž"); pet.getSex(); // samec pet.getName(); // Olivere

Ve výše uvedeném kódu je jmenná proměnná vnější funkce přístupná vnitřním funkcím a neexistuje žádný jiný způsob přístupu k vnitřním proměnným než prostřednictvím vnitřních funkcí. Vnitřní proměnné vnitřních funkcí fungují jako bezpečné úložiště pro vnější argumenty a proměnné. Obsahují „trvalá“ a „zapouzdřená“ data, se kterými mohou vnitřní funkce pracovat. Funkce ani nemusí být přiřazeny k proměnné nebo mít název.

Var getCode = (function() ( var apiCode = "0]Eal(eh&2"; // Kód, který nechceme, aby ho mohli upravovat lidé zvenčí... return function() ( return apiCode; ); ))() getCode(); // Vrátí apiCode

Existuje však řada úskalí, na která je třeba při používání uzávěrů dávat pozor. Pokud uzavřená funkce definuje proměnnou se stejným názvem jako název proměnné ve vnějším rozsahu, neexistuje způsob, jak znovu odkazovat na proměnnou ve vnějším rozsahu.

Var createPet = function(name) ( // Vnější funkce definuje proměnnou s názvem "name". return ( setName: function(name) ( // Přiložená funkce také definuje proměnnou s názvem "name". name = name; // Jak získáme přístup k "jménu" definovanému vnější funkcí? ) ) )

Použití objektu arguments

Argumenty funkce jsou udržovány v objektu podobném poli. V rámci funkce můžete adresovat argumenty, které jí byly předány, následovně:

argumenty[i]

kde i je pořadové číslo argumentu počínaje nulou. První argument předaný funkci by tedy byly argumenty . Celkový počet argumentů je označen arguments.length .

Pomocí objektu arguments můžete volat funkci s více argumenty, než je formálně deklarováno, že přijímá. To je často užitečné, pokud předem nevíte, kolik argumentů bude funkci předáno. Pomocí arguments.length můžete určit počet argumentů skutečně předávaných funkci a poté přistupovat ke každému argumentu pomocí objektu arguments.

Uvažujme například funkci, která zřetězí několik řetězců. Jediným formálním argumentem funkce je řetězec, který určuje znaky, které oddělují položky, které mají být zřetězeny. Funkce je definována následovně:

Funkce myConcat(separator) ( var result = ""; // inicializace seznamu var i; // iterace přes argumenty pro (i = 1; i< arguments.length; i++) { result += arguments[i] + separator; } return result; }

Této funkci můžete předat libovolný počet argumentů a zřetězí každý argument do řetězce „seznam“:

// vrátí "red, orange, blue, " myConcat(", ", "red", "orange", "blue"); // vrátí "slon; žirafa; lev; gepard; " myConcat("; ", "slon", "žirafa", "lev", "gepard"); // vrátí "šalvěj. bazalka. oregano. pepř. petržel. " myConcat(". ", "šalvěj", "bazalka", "oregano", "pepř", "petržel");

Poznámka: Proměnná arguments je "jako pole", ale ne pole. Je podobný poli v tom, že má očíslovaný index a vlastnost length. Nemá však všechny metody manipulace s polem.

Zavedení funkcí šipek ovlivnily dva faktory: kratší funkce a jejich nezávaznost.

Kratší funkce

V některých funkčních vzorech jsou kratší funkce vítány. Porovnat:

Var a = [ "Vodík", "Helium", "Lithium", "Beryllium" ]; var a2 = a.map(funkce(y) ( return s.length; )); console.log(a2); // protokoly var a3 = a.map(s => s.length); console.log(a3); // protokoly

Žádné oddělené

Dokud nefungovala šipka, každá nová funkce definovala svou vlastní hodnotu (nový objekt v případě konstruktoru, nedefinovaný ve volání funkcí, základní objekt, pokud je funkce volána jako "objektová metoda" atd.). To se ukázalo jako méně než ideální s objektově orientovaným stylem programování.

Funkce Person() ( // Konstruktor Person() definuje `toto` jako sebe samého. this.age = 0; setInterval(funkce growUp() ( // V nonstrict režimu funkce growUp() definuje `toto` // jako globální objekt, který se liší od `this` // definovaného konstruktorem Person() this.age++; ), 1000); ) var p = new Person();

V ECMAScript 3/5 byl tento problém vyřešen přiřazením hodnoty v tomto proměnné, kterou lze uzavřít.

Function Person() ( var self = this; // Někteří volí `to` místo `self`. // Vyberte si jednu a buďte konzistentní. self.age = 0; setInterval(function growUp() ( // Zpětné volání odkazuje na proměnná `self`, jejíž // hodnota je očekávaný objekt. self.age++; ), 1000); )