Expresivní JavaScript: Funkce. Funkce JavaScriptu

V této kapitole:

Funkce jsou jedním z hlavních způsobů, jak kombinovat příkazy do logicky souvisejících bloků. V JavaScriptu je funkce skupina výrazů, které provádějí konkrétní úlohu, kombinované pod společným názvem.

Na rozdíl od většiny ostatních programovacích jazyků JavaScript nerozlišuje mezi skutečnými funkcemi a procedurami. Stejně jako funkce jsou i procedury programovými bloky. Výsledky provádění procedur však přímo ovlivňují provádění programu, zatímco funkce musí vracet hodnoty. Z tohoto pohledu lze za procedury považovat i funkce JavaScriptu.

Definování a volání funkcí

Před voláním a použitím funkce je nutné ji definovat. Definování funkcí v JavaScriptu má následující syntaxi:

Funkce Názevfunkce (argumenty) ( blok výrazu )

Funkce se tedy skládá z následujících částí, kterým předchází klíčové slovo function:

  • identifikátor definující název funkce;
  • seznam argumentů uzavřených v závorkách a oddělených čárkami;
  • Příkazy JavaScriptu uzavřené ve složených závorkách. Tyto příkazy mohou zahrnovat volání jiných funkcí nebo dokonce funkce samotné (rekurze).

V nejjednodušším případě nemusí existovat žádné argumenty a blok operací může být reprezentován jedním operátorem:

Function MyFirstFunc () ( var MyMessage="Toto je moje funkce!"; alert(MyMessage); )

Zde jsme definovali funkci, která zobrazí okno se zprávou „Toto je moje funkce!“ Je třeba poznamenat, že i když funkce nebere žádné argumenty, měla by mít za svým názvem pár závorek.

POZOR
Důležitá poznámka by měla být provedena ohledně proměnných deklarovaných v tělech funkcí. Takové proměnné jsou programu viditelné pouze v rámci funkce, ve které jsou definovány. Takže v příkladu MyFirstFunc je přístup k proměnné MyMessage možný pouze uvnitř této funkce, ale ne mimo ni.

Funkce ale častěji berou jako argumenty nějaké hodnoty. Vezměme si jako příklad dříve diskutovaný blok, který vypočítává seznam čísel, kterými je 100 dělitelné beze zbytku. Pokud tento blok přesunete do samostatné funkce, můžete jej použít k zobrazení seznamu dělitelů pro libovolné číslo. K tomu potřebujeme pouze jeden argument, který určí číslo, pro které potřebujeme takový seznam získat:

Funkce zbytek_free(j) (var i=0; while (i nedefinováno, protože z bylo lokálně změněno

Funkční parametry

Funkce lze spouštět s libovolným počtem parametrů.

Pokud je funkci předáno méně parametrů, než je v definici, pak se chybějící parametry považují za nedefinované.

Následující funkce vrací čas potřebný k překonání vzdálenosti při stejné rychlosti.

Při prvním spuštění funkce pracuje s argumenty distance=10 , speed=undefined . Tato situace, pokud je podporována funkcí, obvykle poskytuje výchozí hodnotu:

// pokud je rychlost nepravdivá hodnota (nedefinováno, 0, nepravda...) - dosadit 10 rychlost = rychlost || 10

Provozovatel || v JavaScriptu nevrací true/false , ale samotnou hodnotu (první, která je převedena na true).

Proto se používá k nastavení výchozích hodnot. V našem volání bude rychlost počítána jako nedefinovaná || 10 = 10.

Výsledek tedy bude 10/10 = 1.

Druhé spuštění je standardní.

Třetí běh specifikuje několik dalších argumentů. Funkce neumožňuje práci s dalšími argumenty, takže jsou jednoduše ignorovány.

No, ve druhém případě neexistují vůbec žádné argumenty, takže distance = undefined , a máme výsledek dělení undefined/10 = NaN (Not-A-Number, došlo k chybě).

Práce s neurčeným počtem parametrů

Bezprostředně před vstupem do těla funkce se automaticky vytvoří objekt arguments, který obsahuje

  • Volejte argumenty počínaje nulou
  • Délka ve vlastnosti length
  • Odkaz na samotnou funkci ve vlastnosti volaného
  • Například,

    Funkce func() ( for(var i=0;i alert(3)

    Příklad předání funkce odkazem

    Funkci lze snadno předat jako argument jiné funkci.

    Například map vezme funkci func, použije ji na každý prvek pole arr a vrátí výsledné pole:

    Var map = function(func, arr) ( var result = for(var i=0; i [ okno, "jeden", "dva" ]
    Počkejte. Odkud pochází objekt okna? Proč se to rovná oknu?

    V JavaScriptu, bez ohledu na to, zda je skript spuštěn v prohlížeči nebo v jiném prostředí, je vždy definován globální objekt. Jakýkoli kód v našem skriptu, který není „vázán“ na nic (tj. mimo deklaraci objektu), je ve skutečnosti v kontextu globálního objektu. V našem případě není makeArray pouze funkcí, která „chodí“ sama o sobě. MakeArray je ve skutečnosti metoda okna globálního objektu (v případě spuštění kódu v prohlížeči). Je snadné dokázat:
    alert(typeof window.methodThatNeexistuje); // => undefined alert(typeof window.makeArray); // => funkce
    To znamená volání makeArray("jeden", "dva"); je ekvivalentní volání window.makeArray("jeden", "dva"); .

    Je mi smutno, že je to nejběžnější způsob volání funkcí, protože to znamená přítomnost globální funkce. A všichni víme, že globální funkce a proměnné nejsou nejlepší formou v programování. To platí zejména pro JavaScript. Vyhněte se globálním definicím a nebudete litovat.

    Pravidlo č. 1 volání funkce: Pokud je funkce volána přímo, bez určení objektu (například myFunction()), bude hodnota tohoto globálního objektu (okno, pokud je kód spuštěn v prohlížeči).

    Volání metody Vytvořme jednoduchý objekt a udělejme z makeArray jeho metodu. Objekt deklarujeme pomocí doslovného zápisu a poté zavoláme naši metodu:
    // vytvoření objektu var arrayMaker = ( someProperty: "nějaká hodnota", make: makeArray ); // volání metody make() arrayMaker.make("jeden", "dva"); // => [ arrayMaker, "jeden", "dva" ] // alternativní syntaxe, použijte hranaté závorky arrayMaker["make"]("jeden", "dva"); // => [ arrayMaker, "jeden", "dva" ]
    Vidíte ten rozdíl? Hodnota toho je v tomto případě samotný objekt. Proč ne window , jako v předchozím případě, protože deklarace funkce se nezměnila? Tajemství je v tom, jak jsou funkce předávány v JavaScriptu. Funkce je standardní typ JavaScriptu, který je ve skutečnosti objektem, a jako každý jiný objekt lze funkce předávat a kopírovat. V tomto případě jsme v podstatě zkopírovali celou funkci, včetně seznamu argumentů a těla, a přiřadili výsledný objekt vlastnosti make objektu arrayMaker. To je ekvivalentní tomuto prohlášení:
    var arrayMaker = ( someProperty: "Nějaká hodnota"; make: function (arg1, arg2) ( return [ this, arg1, arg2]; ) );
    Pravidlo #2 volání funkce: Ve funkci volané pomocí syntaxe volání metody, jako je obj.myFunction() nebo obj["myFunction"]() , bude mít hodnotu obj .

    Nepochopení tohoto obecně jednoduchého principu často vede k chybám při zpracování událostí:
    function buttonClicked())( var text = (toto === okno) ? "okno" : this.id; alert(text); ) var button1 = document.getElementById("btn1"); var button2 = document.getElementById("btn2"); button1.onclick = buttonClicked; button2.onclick = function())( buttonClicked(); );
    Po kliknutí na první tlačítko se zobrazí zpráva "btn1" protože v tomto případě voláme funkci jako metodu a ta uvnitř funkce získá hodnotu objektu, ke kterému tato metoda patří. Kliknutím na druhé tlačítko se zobrazí "okno" protože v tomto případě voláme buttonClicked přímo (tj. ne jako obj.buttonClicked()). Totéž se stane, když tagu elementu přiřadíme handler události, jako v případě třetího tlačítka. Kliknutím na třetí tlačítko se zobrazí stejná zpráva jako na druhé.

    Při používání knihoven jako jQuery na to nemusíte myslet. jQuery se postará o přepsání této hodnoty v obslužné rutině události tak, aby tato hodnota byla prvkem, který vyvolal událost:
    // použijte jQuery $("#btn1").click(function() ( alert(this.id); // jQuery zajistí, že "toto" je tlačítko ));
    Jak jQuery dokáže změnit hodnotu tohoto? Přečtěte si níže.

    Další dva způsoby: apply() a call() Je logické, že čím častěji funkce používáte, tím častěji je musíte předávat a volat v různých kontextech. Často je potřeba tuto hodnotu přepsat. Pokud si pamatujete, funkce v JavaScriptu jsou objekty. V praxi to znamená, že funkce mají předem definované metody. apply() a call() jsou dvě z nich. Umožňují vám přepsat tuto hodnotu:
    var auto = ( rok: 2008, model: "Dodge Bailout" ); makeArray.apply(auto, [ "jeden", "dva" ]); // => [ auto, "jeden", "dva" ] makeArray.call(auto, "jedno", "dva"); // => [ auto, "jeden", "dva" ]
    Tyto dvě metody jsou velmi podobné. První parametr toto přepíše. Rozdíly mezi nimi jsou v následujících argumentech: Function.apply() přijímá pole hodnot, které budou předány funkci, zatímco Function.call() přijímá argumenty samostatně. V praxi je podle mého názoru pohodlnější použít apply() .

    Pravidlo #3 volání funkce: Pokud chcete přepsat hodnotu této hodnoty bez kopírování funkce do jiného objektu, můžete použít myFunction.apply(obj) nebo myFunction.call(obj) .

    Konstruktory Nebudu se podrobně zabývat deklarováním vlastních typů v JavaScriptu, ale myslím, že je nutné připomenout, že v JavaScriptu nejsou žádné třídy a každý vlastní typ potřebuje konstruktor. Navíc je lepší deklarovat metody vlastního typu pomocí prototype , což je vlastnost funkce konstruktoru. Vytvořme si vlastní typ:
    // deklarujte funkci konstruktoru ArrayMaker(arg1, arg2) ( this.someProperty = "nezáleží"; this.theArray = [ this, arg1, arg2 ]; ) // deklarujte metody ArrayMaker.prototype = ( someMethod: function () ( alert( "Voláno nějakou metodou" getArray: function () ( return this.theArray; ) ); var am = new ArrayMaker("jeden", "dva"); var other = new ArrayMaker("první", "druhý"); am.getArray(); // => [ am, "jeden", "dva" ]
    Důležitá věc v tomto příkladu je přítomnost operátoru new před voláním funkce. Pokud by tomu tak nebylo, šlo by o globální volání a vlastnosti vytvořené v konstruktoru by patřily globálnímu objektu. To nepotřebujeme. Kromě toho konstruktory obvykle nevracejí hodnoty explicitně. Bez operátoru new by konstruktor vrátil undefined, s ním vrátí toto. Za dobrý styl se považuje pojmenovávat konstruktory velkým písmenem; To vám připomene potřebu nového operátora.

    Jinak bude kód uvnitř konstruktoru pravděpodobně podobný kódu, který byste napsali v jiném jazyce. Hodnota tohoto je v tomto případě nový objekt, který vytváříte.

    Volání funkce Pravidlo č. 4: Při volání funkce s operátorem new bude jeho hodnotou nový objekt vytvořený běhovým prostředím JavaScriptu. Pokud tato funkce nevrátí žádný objekt explicitně, bude vrácena implicitně.

    Závěr Doufejme, že pochopení rozdílu mezi různými způsoby volání funkcí vám pomůže zlepšit váš kód JavaScript. Někdy je obtížné zachytit chyby související s touto hodnotou, takže má smysl jim předem předcházet.

    
    Nahoru