JS Uzavření. Obvody v JavaScriptu: Praktický příklad, funkce a pravidla

Ahoj všichni! V tomto článku se podíváme na co je uzavření v JavaScriptu.

To je docela jednoduché téma, ale vyžaduje pochopení. Nejprve se podívejme na to, co se stane uvnitř funkce.

Funkce pozdrav (jméno) (
// lexicalenvironment \u003d (Jméno: "Nikolai", text: undefined)
var text \u003d "Dobrý den," + jméno;
// lexicalenvironment \u003d (Jméno: "Nikolai", text: "Ahoj, Nikolai")
Výstraha (text);
}

Pozdrav ("Nikolai");

Co se tady děje a co je Lexicalenvironment.? Pojďme to přijít.

Po volání funkce, vytvoří objekt Lexicalenvironment.Ve kterých jsou zaznamenány všechny místní proměnné a funkce, jakož i odkaz na vnější rozsah (o tom později). V našem případě máme místní proměnnou název.který má okamžitě hodnotu (pak jsme projdeme) a toto "Nikolai". V jednom z článků jsem však napsal, ale připomínám vám, že výklad zná vše o všech proměnných předem. Je to o tom, že na samém počátku funkce má proměnnou tEXT.Interpreter o tom ví, ale protože jsme dosud nedosáhli úkolu této proměnné nějakého druhu, to je rovnocenné nedefinovaný.. Nyní přiřadí variabilní hodnotu a náš objekt Lexicalenvironment. Změny. Jeho majetek tEXT. To se stává skutečností, že jsme zaznamenali ("Ahoj, Nikolai" v našem případě). Po vypracování funkce objekt Lexicalenvironment. Zničit. S následnými volání bude opět vytvořena atd.

Nyní se obrátíme k dalšímu příkladu. Řekni mi, co bude v tomto případě odvozeno?

Var b \u003d 2;
FUNKCE X (A) (
výstraha (A + B);
}
x (1);

Myslel? Myslím, že většina zodpovězila, že se zobrazí číslo 3, a to je správná odpověď, ale můžete vám říci, jak se tlumočník dozvěděl o proměnné b.? Koneckonců to není v tělesné funkci. Pokud ne, rozumme.

Ve skutečnosti javaScript. Je tu skrytá vlastnost [] . Když je funkce deklarována, je vždy někde deklarována. Tato funkce může být v jiné funkci, může být v globálním objektu atd. V našem případě je funkce deklarována v globálním objektu. okno.proto majetek x. [] \u003d Okno.

Var b \u003d 2;
Funkce x (a) (// x. [] \u003d Okno
// lexicalenvironment \u003d (A: 1) -\u003e Okno
výstraha (A + B);
}
x (1);

Tato šipka má objekt Lexicalenvironment. - Jedná se o odkaz na vnější rozsah a tento odkaz je založen majetkem. [] . Takže v objektu Lexicalenvironment. Budeme mít odkaz na externí objekt. okno.. Když tlumočník hledá proměnnou, pak ho poprvé vyhledá v objektu Lexicalenvironment.Pak, pokud nenašel proměnnou, pak to vypadá v odkazu, jde do externího rozsahu a hledá to tam a tak až do konce. Pokud nenašel tuto proměnnou kdekoli, bude to chyba. V našem případě proměnná a. Tlumočník bude trvat z objektu Lexicalenvironment.a proměnná b. Od objektu okno.. Samozřejmě, pokud máme místní proměnnou b. S určitou hodnotou bude zaznamenán v objektu Lexicalenvironment. A následně bude odebrán odtud, a ne z vnějšího pole viditelnosti.

DŮLEŽITÉ! Pamatujte si tu vlastnost [] Je instalován místem, kde byla funkce deklarována, a není způsobena, proto kód níže zobrazuje číslo 3, a ne 5, jak si někteří mohou myslet.

Bar B \u003d 2;
FUNKCE X (A) (
výstraha (A + B);
}

FUNKCE Y () () (
var b \u003d 4;
x (1);
}

Bylo to předběžné pochopení, jak to všechno funguje, a bylo pro vás snazší pochopit, jak území fungují. A teď se obrátíme přímo na téma článku.

Jak jsem řekl, objekt Lexicalenvironment. Pokaždé je zničeno pokaždé po provedení funkce a je vytvořen znovu při opětovném volání. Co když chceme uložit tato data? Ty. Chceme, aby bylo vše zaznamenáno Lexicalenvironment. Nyní byl zachován a byl použit pro následující výzvy? Je to pro to uzavření.

Funkce pozdrav (jméno) (
// lexicalenvironment \u003d (název: "Nikolai")
Funkce návratu () (// [] \u003d lexicalenvironment
Výstraha (jméno);
};
}

Var func \u003d pozdrav ("nikolai");
pozdrav \u003d null;
Func ();

Podívejme se, co jsme to udělali. Nejprve vytváříme funkci pozdrav.ve kterém je název prošel. Funkce vytvoří objekt Lexicalenvironment.kde je vlastnost vytvořena (naše místní variabilní) název. A ona je přidělena jméno "Nikolai". A nyní DŮLEŽITÉ: Vrátíme další funkci z funkce, uvnitř, ve které odvodíme upozornění. proměnná název.. Dále přidělíme proměnnou func. Hodnota vrácená z funkce pozdrav.A tato hodnota je náš funkce, která zobrazuje název. teď jsme pozdrav. Přidělíme se nULA. Právě zničíme naši funkci pozdrav., nicméně, když voláme func.Pak uvidíme hodnotu proměnné název.("Nikolai") Funkce pozdrav.. Jak vám to může říct? A velmi jednoduché. Ta věc je, že naše vrácená funkce má také majetek. [] který odkazuje na vnější rozsah viditelnosti, a tento vnější rozsah v našem případě je objekt Lexicalenvironment. Naše funkce pozdrav.. Proto i přes skutečnost, že odstraníme naši funkci pozdrav., objekt Lexicalenvironment. Není vymazán a zůstal v paměti a zůstane v paměti, dokud není alespoň jeden odkaz. Máme tento odkaz - naše vrácená funkce, která používá proměnnou název. tohoto zařízení Lexicalenvironment..

Takže, teď uveďte definici co je uzavření.

Obvod - Funkce se všemi proměnnými, které jsou k dispozici.

No, článek se ukázal docela objemný, ale to je jen proto, že jsem se snažil popsat celý proces práce uzavření. Chcete-li konsolidovat, chci přinést jednoduchý příklad - metr používající téma právě studoval. Prosím, vypořádejte se s kódem a psát do komentářů, jak a proč to funguje. Pokud něco nechápete, můžete také položit otázku. Děkuji za pozornost!

Funkce MakeCounter () ()
VAR CurrentsCount \u003d 0;

Návratová funkce () ()
CurrentCount ++;
Návratnost proudů;
};
}

Var counter \u003d makecounter ();
Čítač ();
Čítač ();
Výstraha (čítač); // 3.

V JavaScript funkce Lze popsat nejen jeden po druhém, ale také jeden uvnitř druhé. Když máte jednu funkci, je vnitřní bušení přístup k střídavé externí funkci.

Funkce externí (x) (var tmp \u003d 3; funkce interní (y) (výstraha (výstraha (x + y + (++ tmp)); // odstraní 16) vnitřní (10);) vnější (2);

Tento kód vždy dává 16, protože vnitřní funkce vidí x, což je proměnná v externí funkci funku. V tento případ Funkce argumentu. Také interní () může vidět tmp z externího ().

To se nazývá uzavření nebo uzavření. Pokud přesněji se uzavírání nazývá externí funkce, a vše uvnitř se nazývá uzavírání prostředí nebo prostředí uzavření.

Někdy se říká, že uzavření je funkcí, která vrátí funkci, je nesprávně, aby pojmenovala funkci uzávěru, že interní funkce platí pro proměnnou z vnější strany jeho rozsahu.

Funkce FOO (X) (VAR TMP \u003d 3; návratová funkce (Y) (upozornění (upozornění (X + Y + (++ (++ TMP)); // bude také upozornit 16)) var beler \u003d foo (2); // Bar je nyní uzávěrem. Bar (10);

Výše uvedená funkce se zobrazí také 16, protože bar dokonce i po dokončení foo je i nadále přístup k X a TMP, i když se v proměnné baru není v rozsahu, ve kterém byly deklarovány.

Zároveň, protože proměnná TMP je stále uvnitř sloupce, stále zvyšuje každý časový volání.

Tady nejjednodušší příklad Obvod:

Var a \u003d 10; Funkční test () (konzole.log (a); // Závěr 10 konzoly.log (b); // Závěr 6) var b \u003d 6; test ();

Když začnete funkci v JavaScriptu, je pro něj vytvořeno prostředí, tj. Seznam všech proměnných viditelných pro ni, a to nejen argumenty a proměnné, které jej v něm prohlásily, ale i vně, v tomto příkladu je to " "A" B ".

Můžete vytvořit více než jeden uzávěr v jednom prostředí, což je vrátíte do pole, objektu nebo připojení k globální proměnné. V tomto případě budou všichni pracovat stejný X nebo hodnota TMP bez vytváření jednotlivých kopií.

Vzhledem k tomu, že v našem příkladu X je číslo, pak jeho hodnota kopírovat Ve foo jako jeho argument x.

Na druhé straně JavaScript vždy používá odkazy, když jsou objekty přenášeny. Pokud jste nazývali foo s objektem jako argument, pak zpětné uzavření by vrátilo odkaz na původní objekt!

Funkční foo (x) (var tmp \u003d 3; návratová funkce (y) (výstraha (výstraha (x + y + tmp); x.memb \u003d x.memb? X.memb + 1: 1; výstraha (x.memb);) ) Var věku \u003d číslo (2); var bar \u003d foo (věk); // Bar je nyní uzávěrem odkazem na věk. Bar (10);

Jak se očekávalo, každý volací panel (10) zvyšuje X.Memb. To, co byste možná nečekali, takže X pokračuje v závislosti na stejném objektu jako věk! Po dvou volání bar, věk.Memb bude roven 2! Mimochodem, dojde k úniku paměti v objektů HTML.

V programování, zavírání nebo v anglickém jazyce verze "Závěrka" je metoda pro implementaci kontextového závazného názvu v prvních třídách. Procerně je to záznam, který umožňuje funkci spolu s médiem. Životní prostředí je porovnání každé volné funkce s hodnotou nebo odkazem zvanou zavíráním JavaScriptu. Umožňuje přístup k zachycených proměnných prostřednictvím kopií hodnot nebo odkazů, i když jsou způsobeny mimo oblast.

Koncepce uzávěrů

Uzavření bylo vyvinuto v šedesátých letech pro mechanické posouzení výrazů ve výpočtu a aplikovány v roce 1970 jako prvek programovacího jazyka PAL pro podporu funkcí první třídy s lexikální sférou. Peter Landin definoval termín "uzavření" v roce 1964 se střední a řídicí částí používanou na stroji SECD, aby posoudil výrazy lambda spojené s lexikálním prostředím, což vedlo k jejich uzavření nebo uzavření JavaScriptu.

Takové vysvětlení bylo zařazeno do roku 1975 jako lexicky omezená verze LISP a byla rozšířená. Lexikální prostředí je v programu různé platné proměnné. Skládá se z interního lexického média a odkazy na vnější prostředí zvané neokální proměnné.

Lexicní uzávěry v JavaScriptu jsou funkcemi s vnějším prostředím. Stejně jako v JavaScriptu mají všechny proměnné odkaz na typ. JS používá pouze vazbu odkazem - což odpovídá C ++ 11, a životnost ne-lokálních proměnných pořízených funkcí je distribuována při životnosti funkce.

Obvody v JavaScriptu se obvykle zobrazují v jazycích s prvotřídním hodnotami. Tyto jazyky vám umožňují přenášet funkce jako argumenty. A také se vraťte z volání funkcí a připojte se k názvům proměnných. To se děje jako jednoduché typy, jako jsou struny a celá čísla.

V tomto příkladu se výraz lambda (lambda (\u003e \u003d (book-prodejní kniha) práh) se objeví uvnitř funkce best-selling-knih. Když se vypočítá výraz lambda, obvod vytvoří uzávěr sestávající z kódu pro expresi lambda a odkaz na práhovou proměnnou, která je volná proměnná v expresi lambda. Uzávěr je pak přenášen funkcí filtru, která ji opakovaně způsobuje, že by bylo možné stanovit, které knihy by měly být přidány do seznamu výsledků a které by měly být vyřazeny.

Vzhledem k tomu, že dojde k uzávěru v hodnotě prahu, může to použít pokaždé, když jeho filtrační příčiny. Samotná funkce filtru lze definovat dokonale samostatný soubor. Zde je stejný příklad, přepsaný v JS. To ukazuje, jak uzávěry pod kapotou v práci JavaScriptu.

Klíčové slovo se zde používá namísto globální funkce filtru, ale zbytek struktury a účinek kódu je stejný. Funkce může vytvořit blíže a vrátit ji, protože v tomto případě prožívá provádění funkce s proměnnými F a DX pokračovat v funkci po derivátu, i když provedení opustilo jejich rozsah, a už nejsou viditelné.

V jazycích, bez zavírání, životnost automatické lokální proměnné se shoduje s prováděním rámečku zásobníku, kde je tato proměnná deklarována. V jazycích s JavaScriptem, uzávěry a funkce IIFe, proměnné musí i nadále existovat, dokud nebudou mít žádné stávající zámky na ně odkazy. To je nejčastěji implementováno pomocí nějakého tvaru sbírky odpadků.

Výhodou uzávěru je, že si zachovává rozsah, "řetězec viditelnosti" vnějšího nebo "rodičovského" kontextu provedení. Takové chování lze použít několika způsoby a stal se užitečným nástrojem, který zabrání různé chyby JavaScriptu. Jedním z nejčastějších je problém "smyček".

Problém s cyklem dochází, když uživatel vytvoří funkci v cyklu a očekává aktuální hodnotu proměnné v tomto nová funkceI když se změní v kontextu cyklů před voláním nové funkce. Uzávěry používané tímto způsobem již nemají referenční transparentnost, a proto již nejsou čisté funkce, ale jsou běžně používány v nečistých funkčních jazycích, jako je režim. Abychom pochopili, co se zavírá v JavaScriptu, musíte zvážit případy použití. Ve skutečnosti mají v praxi mnoho aplikací:

  1. Mohou být použity pro stanovení řídicích konstrukcí. Například všechny standardní struktury pro správu Smalltalk, včetně větví (If / pak / Else) a cyklů (zatímco a pro), jsou určeny za použití objektů, jejichž metody se uzavírají. Uživatelé mohou také snadno použít uzávěry pro určení řídicí struktury. V jazycích, které implementují účel, můžete vytvořit své multifunkční médium, což vám umožní komunikovat důvěrně a změnit toto prostředí. Uzavření se používá k implementaci objektových systémů.
  2. Vytváření soukromých i veřejných variabilních metod pomocí šablon modulu. Vzhledem k tomu, že vrácené funkce zdědí oblast rodičovské funkce, jsou k dispozici všem proměnným a argumentům v této souvislosti.
  3. Je užitečné v situaci, kdy funkce používá stejný zdroj pro každý hovor, ale také vytváří samotný zdroj. Tato okolnost činí metodou neúčinnou, která je vyloučena výhradně uzavřením.

Podle MDN (Mozilla Developer Network) "uzávěry jsou funkce s nezávislými proměnnými, které" pamatují "prostředí jeho stvoření". A zpravidla, pokud je funkce dokončena, jeho místní proměnné již neexistují. Pochopte, jak uzávěr v JavaScriptu funguje, můžete zvážit několik mechanismů. První je formální logika. Například použití funkce logname, která vezme jeden název jako parametr a registruje jej. Pak vytvořit cyklus pro procházení seznamu jmen, nastavit časový limit a potom zavolejte funkci LOGNAME procházející v aktuálním názvu.

V prvním jazyce, můžete manipulovat stejně jako jiné typy dat, například int nebo řetězec. Pouze tento mechanismus umožňuje například vytvořit neuvěřitelné věci, například přiřadit proměnnou funkci na následné volání nebo přenášet ji jako parametr jiné funkce.

Tento princip používá mnoho struktur, stejně jako manipulátory akcích DOM. Za prvé, událost je "poslech", pak přiřadit funkci zpětného volání, která má být volána pokaždé, když je událost spuštěna.

Anonymní funkce je funkce bez jména. Prakticky začínající programátoři se s nimi setkávají, aniž by pochopili hru s čísly. Například provádění adiční operace, můžete projít proměnnými, například:

  • var x \u003d 3;
  • y \u003d 5;
  • var z \u003d x + y.

Nebo pokud nemáte v úmyslu re-procesní čísla: var z \u003d 3 + 5;

Jedná se o anonymní pokoje. Pro anonymní funkce je můžete prohlásit, když jsou používány "na mouchu" - bez průchodu proměnné. Například vezměte funkci z dříve:

(Alert ("Ceci Est Uni Fonchan Anonyme");

Kromě toho existuje alternativní syntaxe deklarace funkce, která zdůrazňuje, že obě funkce mohou být anonymní a odkazují na jednoduché proměnné, což je pohodlný způsob, jak nainstalovat funkci zpětného volání.

Ve skutečnosti je to stejný mechanismus, ale z tohoto hlediska vám umožní vidět, jak je funkce zavřená zevnitř. Jak je vidět, protože funkce jsou proměnné, jako ostatní, není důvod, pro který nemohou být definovány lokálně. V nulovém řádu, jako je C, C ++ a Java, jsou všechny funkce určeny na jedné úrovni viditelnosti ve stejné třídě nebo na globální úrovni. Na druhé straně, v JavaScriptu, místní funkce zmizí, stejně jako ostatní místní proměnné, jakmile končí rodičovská funkce, takže není viditelná z jiných funkcí.

To je vlastně obtížné, ale JavaScript má způsob, jak sledovat viditelnost proměnných, a dokonce i dvěma způsoby. Přiřazení globální proměnné v JavaScriptu má stejný mechanismus jako v Java - komplexní objekty, pole, prvky DOM a další jsou přenášeny odkazem, takže v následujícím kódu:

var tab \u003d; Var tabs2 \u003d záložka.

Kde, Tab a Tab2 jsou dva odkazy na stejnou tabulku, technicky tyto indikátory ovládané sběračem odpadků. Funkce jsou také přenášeny odkazem. Proměnná GlobalFn již není skrytá. Řád vám umožní dělat to, co je demonstrováno na příkladu úkolu uzavření JavaScriptu.

To je způsob, jak můžete extrahovat funkci z místního kontextu, pokud funkce splňuje jiné místní proměnné. Jednoduchý příklad: Automatický přírůstek, funkce, která vrátí celé číslo, která se zvyšuje o 1 pokaždé volání. Konkrétně potřebuje funkce Inc, která se chová následovně:

// retourne 0 inc ();

// retourne 1 inc ();

// retourne 2 inc ();

S uzavřením vypadá:

funkční makeinc () (var x \u003d 0; návratová funkce () (vrátí x ++;)) var inc \u003d makeinc ();

V poslední řadě v okamžiku, kdy je vytvořena proměnná Inc, nese některé proměnné, které jsou v tomto případě x. Vytváří určitý neviditelný objekt kolem funkce, která obsahuje tuto proměnnou. Tento objekt je funkce uzavření JavaScriptu. Každá kopie funkce současně bude mít vlastní uzávěr:

var inc1 \u003d makeinc ();

var inc2 \u003d makeinc ();

Jak je vidět, uzavření je v mnoha případech velmi užitečné.

Aby se zabránilo konfliktům názvu proměnné, obvykle se používají obor názvů. V JavaScriptu jsou jmenné prostory objekty jako ostatní.

Přirozeně, A.x a B.x není stejná proměnná. Pokud však stačí spustit skript, aniž byste museli ušetřit proměnné pro zbytek, může být použita anonymní funkce jako uzávěr. To poskytuje mírně podivnou syntaxi. Ačkoli dva kódy uprostřed jsou docela běžné, na druhé straně je funkce, která je kolem, je prováděna "na mouchu". Věnujte pozornost závorkám () na konci. A být schopen učinit uzavření, anonymní funkce Musí být obklopen kulatými závorkami.

V této anonymní funkci použijte místní proměnnou, odstavec. To je skvělý způsob, jak zabránit konfliktům jména nebo nemotornosti, ale také proti ataks XSS. Vlastní proměnné jsou chráněny, nikdo je nemůže změnit tak, aby ovlivnily chování skriptu.

Existuje možnost: (funkce () () (// ...) ());

Zároveň upozornit na permutaci závorek. Rozdíl mezi těmito dvěma možnostmi je velmi obtížné vysvětlit, protože jsou spojeny s tím, jak kód čte lexikální analyzátor. V obou případech je funkce považována za výraz, ale tento výraz není odhadnut současně. Stačí si uvědomit, že bere dva páry kulatých závorek: jeden kolem funkce a jeden za ním.

Programování JavaScriptu v cyklech

Když uživatel provádí velké svazky programování JavaScriptu, je pro to obtížné vyhnout se cyklům. Někdo je blázen, po kterém přicházejí k myšlence, že jakákoli implementace JavaScriptu má vážnou chybu. Pokud vývojář již má cyklus, který nechce převést, aby použil funkci iterátoru, vše, co potřebuje udělat, je uzavření, ve kterém definuje nové proměnné. Opravují aktuální hodnotu proměnných a mění se na každou iteraci. Trik pro zachycení proměnných je, že externí uzávěr se provádí okamžitě během aktuální iterace cyklu. Můžete použít jeden z těchto dvou přibližných přístupů.

Nyní existuje další zjednodušené řešení tohoto problému, protože klíčové slovo je podporováno jak ve Firefoxu, tak v Chrome. to je klíčové slovo Místo variabilního bloku variabilního bloku varu. Pracujte magicky, protože je deklarována nová proměnná J, jehož hodnota, jejíž hodnota je stanovena s uzavřením v cyklu. Je však třeba mít na paměti, že i nadále existuje po skončení stejné iterace cyklu, protože je místně.

Smyčka a funkce

Pro smyčku v JavaScriptu se neobjeví, stejně jako pro cyklus v C nebo Java. Ve skutečnosti to vypadá spíše jako PHP. Nejdůležitější znalosti o cyklech v JS je, že nevytvářejí oblast působení. JS nemá blok sféry, pouze funkce objemu. Tato vlastnost lze považovat za následující fragment:

fUNKCE FOO () (varka \u003d 1;

pro (var i \u003d 0; i< 42; i++) {var baz = i;} /* more code */}

Je jasné, že tento bar je k dispozici v celé funkci. Před první iterací BAZ cyklu bude nedefinováno. Po cyklu bude mít hodnotu 41 (a budu 42). Jakákoliv proměnná deklarovaná kdekoli ve funkci bude k dispozici všude ve funkci a bude platná pouze poté, co byl k němu jmenován.

Okenice a agregace

Uzavření není nic jiného než funkce, uvnitř jiných funkcí a jsou přenášeny do jiného kontextu. Oni se nazývají uzávěr, protože blízko prostřednictvím místních proměnných, to je přístupné do jiných oblastí sféry. Například čas, x definovaný jako parametr foo a var bar \u003d foo (2) () se vrátí 84.

Vrácená funkce FOO má přístup x. To je důležité, protože to pomáhá vývojářům vytvářet funkce uvnitř cyklů v závislosti na proměnných cyklu. Zvažte tento fragment, který přiřazuje procesor pro různé prvky:

// Prvky jsou pole 3 dom prvků varů varu \u003d ["foo", "bar", "BAZ"];

i. I.< l; i++) {var data = values[i];

prvky [i] .onClick \u003d funkce () (výstraha (data);

Hodnota, kterou budou používat výstrahu při stisknutí, bude stejná pro každého, jmenovitě bazén. Do té doby se popisovač událostí nazývá, pro již dokončený. JS nemá blokovou oblast, tj Všechny obsluhy používají odkaz na stejnou datovou proměnnou. Po smyčce bude tato hodnota hodnot. Každá variabilní deklarace vytváří jedno místo v paměti úložiště. V případě, tato data se změní znovu a znovu, pozice v paměti zůstane nezměněna.

Každý popisovač událostí má přístup ke stejné poloze v paměti. Jediným řešením je zadání jiné oblasti, která "opravuje" aktuální hodnotu dat. JS má pouze celou řadu funkcí. Proto je zadána další funkce. Příklad:

funkce CreateeVentHandler (X) (návratová funkce () (výstraha (X);

pro (var i \u003d 0, l \u003d elements.length;

i. I.< l; i++) {var data = values[i];

prvky [i] .onclick \u003d createeventhandler (data);

Funguje, protože hodnota dat bude uložena v místní oblasti, CreateeventHandler a tato funkce se provádí na každé iteraci. Může být napsán krátkou, s použitím spustitelných funkcí okamžitě:

pro (var i \u003d 0, l \u003d elements.length;

i. I.< l; i++) {var data = values[i];

prvky [i] .onClick \u003d (funkce (x) (funkce () (výstraha (výstraha (x);

Praktický příklad uzavření v JavaScriptu

Pokud uživatel zavírá přímo nad kód v prohlížeči, může dojít k problému, protože může provést chybu syntaxe. Pokud kódu provede přímo v prohlížeči, šance jsou velmi vysoké, aby sestavily proces kompilace webového počítače. Možné řešení:

funkční práce (název) (

funkce návratu (téma) (

console.log (co je $ (téma) v $ (jméno));

práce ("javascript") ("uzavření");

Za prvé, funkce je volána a argument název je přenášen. Tato funkce slovní zásoby také vrátí funkci, která také přijímá argument témat. Tato funkce registruje výstup a výstup má přístup k proměnné.

Oblast zasvěcených funkcí není omezena na tuto funkci, takže koncept se nazývá uzavření, protože má přístup k této oblasti externí parametr. Vrácená funkce má přístup k externí lexikální oblasti nebo kontextu. Když vývojář volá funkci, která ji také vrátí, pak poprvé proměnná funkce Vždy k dispozici pro interní funkci. Další příklad s následujícím kódem.

Příklad vnitřní funkce

Přečtěte si více o uzavření v JavaScriptu lze vyprávět na druhém příkladu. Toto naplnění prostředí je zničeno, ale název parametru stále existuje. Je vytvořeno nové interní funkční médium, což je anonymní funkce. Má přístup k oblasti vnějšího lexikálního prostředí.

Tak, v proměnné vnějšího prostředí, stále existuje takovým způsobem, že anonymní funkce má přístup k názvu proměnné tisky v konzole, například "Co je uzávěr v JavaScriptu". Interní anonymní funkce //main.js

funkce Factory () (Var Products \u003d;

i ++) (produkty.Push (funkce () () (konzole.log (i);

) Návratové produkty;

) Var mýdlo \u003d továrna ();

Výsledkem tohoto příkladu je poněkud nevýznamný a rovný 2.

Když mýdlo je mýdlo () nazvaný externí kontextová proměnná, vždy 2, protože v cyklu je podmínka nepravdivá<2, поэтому при этом значение i равно 2, а во время вызова нужно напечатать значение в консоль так, она всегда пишет 2. То же самое для мыла - soap ().

Vytváření funkcí "na Fly"

Můžete vytvořit funkce Funkce - FunctionForfactory, která provádí vlastní úkoly. Výsledná funkce z továrny funkcí bude uzavření, paměťové médium vytvoření.

var FunctionFactory \u003d Funkce (NUM1) (Návrat num1 * num2;

Výše uvedené umožňuje přenášet jedno funkční číslo. Functionfactory pak vrátí uzávěr, zapamatování hodnoty NUM1. Výsledná funkce násobí původní num1 krát hodnotu NUM2, která je vysílána při volaném.

var mult5 \u003d FunctionFactory (5);

var Multi10 \u003d FunctionForfactory (10);

Výše uvedené jednoduše vytvoří funkce Multi5 a Multi10. Nyní můžete odkazovat na některý z těchto funkcí předáním nového čísla pro násobit 5 nebo 10. Nyní můžete zobrazit výsledek.

Uzavření je jedním z nejsilnějších funkcí JavaScriptu, ale nemůže být použito správně bez pochopení podstaty. Jsou poměrně snadné vytvářet náhodou, to je, jak nebezpečné uzavírání JavaScriptu. Jejich stvoření má potenciálně škodlivé účinky, zejména v některých relativně běžných webových prohlížečích prostředí. Aby se zabránilo náhodnému kolizi se nevýhodami a využijte výhod, které nabízejí, je nutné pochopit jejich mechanismus.

V tomto článku se pokusím vysvětlit oblasti viditelnosti a uzavření v JavaScriptu, ve kterých mnoho zkušeností s obtížemi.

Úvod

Existuje několik článků v síti, které se snaží vysvětlit oblasti viditelnosti a uzavření, ale obecně bych řekl, že většina z nich není zcela srozumitelná. Kromě toho, v některých článcích se předpokládá, že jste naprogramován před 15 dalšími jazyky, i když si myslím, že většina lidí psaní na JavaScriptu mají pouze zkušenosti s HTML a CSS, a ne v C nebo Jávě.

V důsledku toho je účelem tohoto článku vysvětlit všem - jaký je rozsah viditelnosti a uzavření, jak fungují, a co je nejdůležitější, jakou jejich výhodu. Před přečtením tohoto článku potřebujete znát základní pojmy o proměnných a funkcích v JavaScriptu.

Oblast viditelnosti

Rozsah rozsahu, kde jsou k dispozici proměnné a funkce, a v jakém kontextu jsou prováděny. Proměnná nebo funkce lze definovat v globální nebo místní oblasti viditelnosti. Proměnné mají tzv funkci viditelnosti funkcí a funkce mají stejný rozsah jako proměnné.

Globální rozsah

Když je něco globální, znamená to, že je k dispozici odkudkoliv v kódu. Zvažte příklad:

var opice \u003d "gorila"; Funkce GreetVisitor () (návratový upozornění ("Ahoj milý blog čtenář!"););

Pokud byl tento kód proveden ve webovém prohlížeči, bude oblast viditelnosti okno, pak bude k dispozici pro vše, co je provedeno v okně.

Místní rozsah

Na rozdíl od globální oblasti viditelnosti je oblast lokální viditelnost, když je něco definováno a dostupné pouze v některém části kódu, jako je funkce. Zvažte příklad:

funkce Talkdirty () (var říkat \u003d "Oh, ty málo vb lover, vy"; návratový záznam (říkat);) výstraha (říkat); // hozen chybu

V tomto příkladu je velitelská proměnná dostupná pouze uvnitř funkce TalkDirty, mimo kterou není definován. Poznámka: Pokud jste byli identifikováni tím, že řeknete bez klíčového slova Var, automaticky se stane globální.

Kromě toho, pokud máte vnořené funkce, interní funkce bude mít přístup k funkcím, ve kterých je vloženo, stejně jako proměnné:

funkce Capitalizename (Return FirstName.tuppercase ();) varitized \u003d kapitalizename (); návrat kapitalizovaný;) výstraha (Savename ("Robert")); // vrací "robert"

Jak jste právě viděli, interní funkce kapitalizename nemusí vysílat žádné parametry, protože Má plný přístup k parametru FirstName v externí funkci SAVENAME. Pro větší jasnost zvažte další příklad:

funkce sourozenci () (var souslings \u003d ["John", "Liza", "Peter"]; Funkce SiblingCount () (VAR Siblingslength \u003d Siblings.Length; Return Siblingslength;) Funkce JoinsiblingNames () (návrat "Mám" + SiblingCount () + "Sourozenci: nn" + sourozenci.Join ("n");) návrat joinsiblingnames ();) výstraha (sourozence ()); // výstupy "Mám 3 sourozenci: John Liza Peter"

Jak vidíte, obě interní funkce mají přístup k siblings Array, a každá interní funkce má přístup k jinému interní funkci stejné úrovně (v tomto případě, JoinSiblingNames má přístup k SiblingCount). Proměnná siblingslengths uvnitř SiblingCount je však dostupná pouze uvnitř této funkce, tj. V této oblasti viditelnosti.

Obvod

Nyní, když máte jasnější myšlenku oblastí viditelnosti, přidáme jim uzávěr. Obvody jsou výrazy, obvykle funkce, které mohou pracovat se sadou proměnných v určitém kontextu. Nebo jednodušší slova, interní funkce, které odkazují na místní proměnné externích funkcí. Například:

funkce přidat (x) (vraťte x + y;);) var add5 \u003d add (5); VAR NO8 \u003d ADD5 (3); Upozornění (NO8); // vrátí 8.

Blipey! Co se tam děje? Pojďme zjistit:

1. Když zavoláme funkce Přidat, vrátí funkci.

2. Tato funkce uzavírá kontext a zapamatuje si, jak je parametr X v této době (tj. V tomto případě hodnota 5)

3. Pokud je výsledek funkce ADD5 přiřazen proměnné ADD5, bude vždy vědět, co X bylo při vytváření této proměnné.

4. Proměnná ADD5 odkazuje na funkci, která bude vždy přidávat hodnotu 5 na jakýkoliv argument k němu.

5. To znamená, že když voláme Add5 s hodnotou 3, bude složit číslo 5 a 3 a vrátí 8.

Ve skutečnosti, v JavaScript světě, funkce Add5 vypadá takto:

funkce ADD5 (Y) (Zpět 5 + y;)

Notoricky známý problém cyklů
Kolikrát jste vytvořili cykly, ve kterých jste chtěli přiřadit hodnotu i jakýmkoliv způsobem, například prvek, a pochopil, že pouze poslední hodnota, kterou jsem byla vrácena?

Špatněodvolání

Podívejme se na tento nesprávný kód, který vytváří 5 prvků , přidává hodnotu I jako text každému prvku a onclick, který se očekává, že bude produkovat výstrahu s hodnotou I pro tento odkaz, tj. Stejnou hodnotu jako v textu prvku. Pak jsou prvky přidány do těla dokumentu:

<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function () { alert(i); }; document.body.appendChild(link); } } window.onload = addLinks;

Každý prvek obsahuje správný text, tj "LINK 0", "LINK 1", atd. Ale jakýkoliv odkaz jste klikli, ukazuje výstrahu s číslem 5. Co je to záležitost? Důvodem je, že hodnota proměnné se zvyšuji o 1 s každou iterací cyklu, a proto OnClick událost není provedena, ale jednoduše platí pro prvek Hodnota se zvyšuje.

Proto cyklus pokračuje v práci, dokud se nestane 5, což je poslední hodnota před odchodem z funkce AddLinks. Dále, pokaždé, když je událost OnClick spuštěna, je přijata poslední hodnota I.

Správné odvolání

Co musíte udělat, je vytvořit uzavření. V důsledku toho, když použijete hodnotu I do události události OnClick , Budu v té době přidělen hodnotu I. Například, jako je tento:

funkce AddLinks () (pro (var i \u003d 0, odkaz; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function (num) { return function () { alert(num); }; }(i); document.body.appendChild(link); } } window.onload = addLinks;

Použití tohoto kódu, pokud kliknete na první prvek, výstraha vydá "0", na druhém - "1" atd. Řešením je, že vnitřní funkce aplikovaná na událost OnClick vytvoří uzávěr, ve kterém se num parametr odvolání, tj. na hodnotu I v té době.

Tato funkce "si pamatuje" požadovanou hodnotu a pak může vrátit odpovídající číslici, když je spuštěna událost OnClick.

Funkce zabezpečeného provádění

Bezpečné provádění funkcí jsou takové funkce, které začínají okamžitě provádět a vytvářejí jejich uzavření. Zvažte příklad:

(Funkce () (VAR DOG \u003d "německý ovčák"; výstraha (pes);)) (); Výstraha (pes); // vrátí nedefinované.

Takže proměnná psa je k dispozici pouze v této souvislosti. Přemýšlejte, skrytý variabilní pes ... Ale moji přátelé, nejzajímavější věc začíná tím! Vyřešil náš problém s cyklem, a to je také základ pro vzor modulu modulu Yahoo JavaScript.

Modul Yahoo JavaScript Modul

Podstatou tohoto vzoru je, že používá bezpečnostní funkci pro vytvoření uzávěru, proto umožňuje využít soukromé a veřejné vlastnosti a metody. Jednoduchý příklad:

vAR Osoba \u003d Funkce () (// Private var Name \u003d "Robert"; Return (GetName: Funkce () (Název návratu), SetName: Funkce (NewName) (Name \u003d NewName;));) (); výstraha (osoba.name); // undefined alert (osoba.getname ()); // "robert" osoba.Setname ("robert nyman"); výstraha (osoba.)); // "Robert Nyman"

Výhodou tohoto přístupu je, že se můžete definovat sami, který bude otevřen ve vašem objektu (a může být změněn) a že uzavřené, které nikdo nemůže kontaktovat nebo změnit. Proměnná názvu je skryta mimo kontext funkce, ale je přístupná funkcím GetName a SetName, protože Vytvářejí uzávěry, ve kterých je odkaz na proměnnou názvu.

Závěr

Upřímně doufám, že po přečtení tohoto článku obdrželi nováčci a zkušení programátoře jasnější představu o tom, jak v pracovních oblastech JavaScriptu pracovních oblastí viditelnosti a uzávěrů. Otázky a recenze jsou vítány, a pokud máte něco důležitého nechat něco, pak mohu aktualizovat článek.

Dobré kódování!

Obvody v JavaScriptu. Slouží k skrynutí variabilních hodnot a úložných funkcí. Bod je, že když je zavřený, je vytvořena jedna funkce, ve které jsou specifikovány proměnné a které v důsledku jeho provozu vrátí jeho vnořenou funkci. Pak v něm (v hlavní funkci) je vytvořena vestavěná funkce, ve které jsou některé operace prováděny s proměnnými funkčními proměnnými a které vrací výsledek těchto operací. Dále se hlavní funkce rovná proměnné - tato proměnná může být vyvolána, kolik času a avšak hodnoty proměnných hlavní funkce budou uloženy a aktualizovány. Je "zavřená".

Jak víte, v JavaScriptu Oblast viditelnosti místních proměnných (deklarované var slíjky) Je to tělo funkce, ve které jsou definovány.

Pokud deklarujete funkci uvnitř jiné funkce, první dostane přístup k proměnným a argumentům druhé:

Kód: Funkce Unterfn (myarg) (
Var myvar;
Funkce innerfn () () ()
// má přístup k myvearu a myargu
}
}

Současně takové proměnné i nadále existují a zůstávají dostupná interní funkce i po externí funkci, ve které jsou definovány, byla provedena.

Zvažte příklad - funkce, která vrací počet vlastních hodnot:

Kód: Funkce CreateCounter () () ()
var numberOfcalls \u003d 0;
Návratová funkce () ()
Vrátit ++ numberofcalls;
}
}
var fn \u003d createCounter ();
fn (); //jeden
fn (); // 2.
fn (); // 3.

V tomto příkladu funkce vrácená CreateCounter používá proměnnou číslování, která uloží požadovanou hodnotu mezi volání (namísto okamžitě zastavení jeho existence s návratem CreateCounter).

Je to pro tyto vlastnosti, že takové "vnořené" funkce v JavaScriptu se nazývají uzávěry (termín, který pochází z programovacích funkčních jazyků) - oni "blíže" proměnné a argumenty funkce, ve kterých jsou definovány.

Aplikace uzávěrů

Zjednodušuje malý příklad výše - odstranit potřebu samostatně volat funkci CreateCounter, takže je příloh a volání ihned po jeho reklamu:

Kód: var fn \u003d (funkce () ()
var numberOfcalls \u003d 0;
Návratová funkce () ()
Vrátit ++ numberofcalls;
}
})();

Takový design nám umožnil vázat údaje na funkci, která zůstala mezi svými výzvami, je jedním z použití uzávěrů. Jinými slovy, s pomocí nich můžeme vytvářet funkce, které mají variabilní stav.

Jiné dobré využití uzávěrů - vytvoření funkcí, a to i vytváření funkcí - to, co někteří by nazývali t.n. Metaprogramování.
Například:

Kód: var createhellofunkce \u003d funkce (jméno) (
Návratová funkce () ()
Alert ("Ahoj," + jméno);
}
}
var sayhellohabrahabr \u003d createhellofunkce ("habrahabr");
sayhellohabrahabr (); // upozornění "hello, habrahabr"

Díky uzavření, vrácená funkce "si pamatuje" parametry přenesené do funkce vytváření, které potřebujeme pro tento druh věcí.

Podobná situace nastane, když nevrátíme interní funkci, a viset na libovolnou událost - protože událost vzniká po splnění funkce, uzávěrka opět pomáhá ztratit data přenášená při vytváření datového procesoru.

Zvažte o něco složitějším příkladem - způsob, který spojuje funkci do určitého kontextu (tj. Objekt, ke kterému toto slovo uvede).

Kód: Function.prototype.bind \u003d Funkce (kontext) (
var fn \u003d to;
Návratová funkce () ()
Vrátit fn.Apply (kontext, argumenty);
};
}
var hellopage \u003d (
Jméno: "Habrahabr",
INIT: Funkce () () ()
Upozornění ("Ahoj," + tento.name);
}
}
//Window.onload \u003d hellopage.init; // alertnul by nedefinoval, protože To označuje okno
window.onload \u003d hellopage.init.bind (hellopage); // teď všechno funguje

V tomto příkladu, s pomocí uzávěru, funkce, spuštěnou vazbu "ohm, si pamatuje počáteční funkci a kontext přiřazený k němu.

Další, zásadně odlišné použití uzávěrů - ochrana dat (zapouzdření). Zvažte následující design:

Kód: (funkce () ()

})();

Samozřejmě, uvnitř uzavření máme přístup ke všem externím údajům, ale má své vlastní. Díky tomu můžeme prostorové části kódu jako design, aby se místní proměnné zavřete mimo přístup venku. (Jedním z příkladů jeho použití lze vidět ve zdrojovém kódu knihovny JQuery, který obklopuje uzavření celého svého kódu tak, aby nevystupovaly pouze proměnné).

Tam je, nicméně, jeden spojený s takovým použitím pasti - význam slova je ztracena uvnitř uzavření. Je řešen následovně:

Kód: (funkce () ()
// nejvyšší to bude pokračovat
)). Volání (toto);

Zvažte další recepci ze stejné série. Bylo to široce populární jeho vývojáři Framework Yahoo UI, volal mu "modul vzor" a psát celý článek na něm v oficiálním blogu.
Pojďme mít objekt (singleton) obsahující všechny metody a vlastnosti:

Kód: var mommodule \u003d (
Jméno: "Habrahabr",
Saypreved: Funkce (jméno) (
Alert ("preved" + název.touppercase ())
},
Tento.Saypreved (tento.name);
}
}
Mymodule.Sayprevedtohabrahabr ();

S pomocí uzavření můžeme provést metody a vlastnosti, které nejsou používány mimo objekt, soukromé (tj. K dispozici pouze pro něj):

Kód: var mommodule \u003d (funkce () ()
Var název \u003d "habrahabr";
Funkce Saypreved () ()
Alert ("preved" + název.touppercase ());
}
Vrátit se (
SayprevedtohabraBR: Funkce () () ()
Saypreved (jméno);
}
}
})();
Mymodule.Sayprevedtohabrahabr (); // výstrahy "preved habrahabr"

Nakonec chci popsat společnou chybu, že mnoho jezdí do hlouposti v případě nevědomosti, jak uzavírá práci.

Mějme řadu odkazů a náš úkolem je, aby to bylo tak, že když kliknete na každý alert, zobrazí se jeho pořadové číslo.
První rozhodnutí, které přijde na mysl vypadá takto:

Kód: pro (var i \u003d 0; i< links.length; i++) {
Výstraha (I);
}
}

Ve skutečnosti se ukáže, že když kliknete na libovolný odkaz, zobrazí se stejné číslo - hodnota odkazu. Proč se tohle děje? V souvislosti s uzavřením, oznámená pomocná proměnná i nadále existuje, s a v okamžiku, kdy klikneme na odkaz. Vzhledem k tomu, že do té doby, kdy cyklus již prošel, zůstane rovna počtu odkazů - tato hodnota jsme viditelní při kliknutí.

Tento problém je řešen následovně:

Kód: pro (var i \u003d 0; i< links.length; i++) {
(Funkce (i) (i)
Odkazy [I] .onClick \u003d Funkce () ()
Výstraha (I);
}
)) (i);
}

Zde, s pomocí dalšího uzávěru, variabilní ", vytváříme ji kopii v místní oblasti viditelnosti v každém cyklu kroku. Díky tomu všechno funguje nyní jako koncipované.

To je vše. Tento článek se samozřejmě netvrdí, že je vyčerpávající, ale někdo, doufám, stále pomáhá přijít na to.

z y.
Pro ukládání hovorů usnadňují použití FUNC_NAME.Attr typu:

Kód: Funkce Countit (Reset) (
pokud (reset ||! countit.cnt) countit.cnt \u003d 0;
vrátit countit.cnt ++;