Kompletní průvodce k funkci arrow v JavaScriptu

  • Šipkové funkce poskytují stručnou syntaxi a lexikon, který dědí kontext, ve kterém jsou definovány, což výrazně zjednodušuje zpětná volání a asynchronní kód.
  • Tradiční funkce udržují dynamicky ovladatelný `this` pomocí `call`, `apply` a `bind` a jsou vhodné pro konstruktory, objektové metody a klasické OOP vzory.
  • Správná kombinace šipkových funkcí s ES6 (metody let, const, destrukturalizace, spread a pole) je klíčem k psaní moderního, neměnného a expresivního kódu v JavaScriptu a Reactu.
  • Vědět, kdy se vyhnout šipkovým funkcím (například jako objektovým metodám nebo konstruktorům), je stejně důležité jako vědět, jak je využít v modulech, obslužných rutinách událostí a funkční logice.

šipka a tato funkce v JavaScriptu

Pokud už nějakou dobu programujete v JavaScriptu, pravděpodobně jste už tisíckrát slyšeli o šipkových funkcích a slavném speciálním chování funkce `this` . A je také docela pravděpodobné, že vám hlava nejednou explodovala při snaze pochopit, proč `this` znamená jednu věc v normální funkci a něco úplně jiného v šipkové funkci.

Zvládnutí těchto dvou konceptů není jen otázka teorie: je klíčové pro psaní moderního kódu v JavaScriptu a Reactu , pochopení fungování obslužných rutin událostí, chování kontextu v rámci tříd, řešení asynchronních zpětných volání v Node.js a proč jsou určité vzory dnes považovány za osvědčené postupy.

Nejprve: rychlý přehled funkcí v JavaScriptu

V JavaScriptu můžete deklarovat funkce několika způsoby a každý způsob má důsledky pro chování funkce `this` , její rozsah platnosti a pro to, kdy je funkce v kódu dostupná.

Deklarace funkce

Klasická deklarace funkce používá klíčové slovo ` function` a název. Tyto typy funkcí jsou „přesunuty“ na začátek rozsahu platnosti, kde jsou deklarovány, což umožňuje volání funkce ještě před její definicí v souboru.

V tradičně deklarované funkci je hodnota `this` určena tím, jak je funkce volána: zda je volána jako metoda objektu, použita s `new` , v striktním režimu, předána metodám `call` , `apply` nebo `bind` atd. Tato flexibilita je sice silná, ale je také zdrojem mnoha chyb ve složitém kódu.

Výraz funkce

Proměnné můžete také přiřadit anonymní nebo pojmenovanou funkci . V takovém případě se samotná funkce nevyvolá; vyvolá se pouze deklarace proměnné (pomocí `var` ), ale nikoli její hodnota. S `let` a `const` nemůžete funkci použít ani před její definiční řádkou kvůli dočasné mrtvé zóně.

Tyto funkce sdílejí stejný dynamický model `this` jako klasické deklarace: jejich hodnota vždy závisí na kontextu volání, takže zůstávají citlivé na to, jak je předáváte jako callback nebo jak je používáte v rámci tříd a objektů.

Jak povolit JavaScript na telefonu Android
Související článek:
Jak povolit JavaScript na telefonu Android

Co přesně jsou šipkové funkce?

Šipkové funkce byly zavedeny s ECMAScript 2015 (ES6) jako pohodlnější, kompaktnější a expresivnější způsob deklarace funkcí, zejména pro zpětná volání a funkcionální programování s metodami jako map , filter nebo reduce.

Jeho základní syntaxe se skládá ze seznamu parametrů, následovaného operátorem => a následně výrazem nebo blokem kódu . Tato kompaktní forma usnadňuje čitelnost kódu v mnoha scénářích, kde jste dříve museli psát dlouhé a opakující se anonymní funkce.

Základní syntaxe šipkových funkcí

Šipkové funkce podporují několik syntaktických variant, všechny založené na stejných pravidlech, ale se zkratkami pro jednodušší případy. Pochopení jednotlivých forem vám pomůže psát čistší kód a rychle rozpoznat, co každá zpětná volání dělá.

  • Bez parametrůPřed šipkou se používají prázdné závorky a za nimi obvykle výraz.
    const getMessage = () => "Hola";
  • Jeden parametrZávorky kolem názvu parametru můžete vynechat, což kód zpřehlední.
    const square = x => x * x;
  • Několik parametrůVždy je nutné použít závorky, které je uzavírají a oddělují čárkami.
    const sum = (a, b) => a + b;
  • Tělo jednoho výrazuPokud nepoužijete složené závorky, výraz se vrátí určitým způsobem. implicitní bez nutnosti psaní zpáteční.
  • Víceřádkové těloPokud používáte složené závorky, musíte napsat zpáteční explicitně vrátit hodnotu, stejně jako v normální funkci.

Častým zdrojem chyb je zapomenutí příkazu return při přechodu z jednořádkové verze na tělo se složenými závorkami, abyste přidali více logiky; vaše funkce najednou začne vracet nedefinovanou hodnotu a není zřejmé proč.

Funkce šipek a literální objekty

Pokud funkce s jedním výrazem typu šipka vrací literální objekt , musíte tento objekt uzavřít do závorek, aby si jej engine nespletl se začátkem funkčního bloku. Je to drobná syntaktická past, která mnoho lidí zaskočí.

Jinak interpret interpretuje klíče jako prázdný blok a vaše funkce nevrátí objekt, ale undefined , což způsobí obtížně sledovatelné chyby při pokusu o přístup k vlastnostem, které nebyly nikdy vráceny.

Funkce šipek a jejich chování

Skutečným rozlišovacím faktorem šipových funkcí není jejich syntaxe, ale jejich model `this` . Zatímco tradiční funkce mají dynamický `this` , který závisí na způsobu jejich volání, šipové funkce mají lexikální `this` ; to znamená, že zachycují `this` rozsahu, ve kterém jsou vytvořeny , a ponechávají ho nezměněný.

To znamená, že v rámci šipkové funkce nelze hodnotu `this` změnit pomocí `call` , `apply` nebo `bind` a také nezáleží na tom, zda ji použijete jako callback v obslužné rutině události nebo ji předáte jiné funkci. Vždy bude mít stejnou hodnotu, jakou měla mimo funkci v době její definice.

Jak to funguje v běžných funkcích?

Ve funkci deklarované s `function` závisí hodnota `this` na kontextu:

  • Pokud funkci zavoláte jako metoda objektu, tento Ukažte na ten objekt.
  • Pokud jej vyvoláte bez kontextu v nestriktním režimu, tento odkaz na globální objekt (okno v prohlížeči, globální v Node.js).
  • Pokud používáte nový, tento pak ukazuje na nově vytvořená instance.
  • Pokud se přihlásíte volání, aplikovat o vážou, můžete vynutit hodnotu tento ručně k objektu dle vašeho výběru.

V striktním režimu, pokud voláte normální funkci bez objektu jako příjemce a bez použití volání nebo podobné, tento bude nedefinovanéProto v mnoha moderních příkladech vidíte funkce, které začínají na 'use strict' aby se předešlo tichým chybám a vynutilo se konzistentnější chování.

Jak to funguje ve funkcích šipek?

V případě šipkových funkcí se `this` při jejich volání nepřepočítává; je převzata přímo z rozsahu platnosti, kde byla definována . To znamená, že se chovají podobně, jako když jsou proměnné zachyceny uzávěrem : dívají se ven a pamatují si tuto hodnotu navždy.

To má několik velmi důležitých důsledků pro váš každodenní život:

  • Nemůžete použít funkci se šipkami jako konstruktérem s novýprotože nemají své vlastní tento ani vhodný prototyp.
  • Volání funkce se šipkou pomocí volání o aplikovat nezmění hodnotu tentoZbytek argumentů však budete moci předat normálně.
  • V metodách objektů vytvořených jako šipkové funkce, tento Nebude ukazovat na objekt, ale na horní prostředí (například okno nebo modul), což je téměř vždy chyba.

Klíčovým poznatkem je, že šipkové funkce jsou ideální, když chcete, aby interní `this` bylo stejné jako externí , ale jsou špatným nápadem, když potřebujete metodu skutečného objektu nebo když chcete vytvořit instanci něčeho pomocí `new`.

Funkce, třídy a React se šipkami

šipka a tato funkce v JavaScriptu

Ve světě Reactu a JavaScriptových tříd obecně je zpracování ` this` citlivým tématem. Komponenty tříd, které dědí z ` React.Component`, používají metody, kde `this` musí konzistentně ukazovat na instanci komponenty, aby mohly přistupovat k ` this.props` a `this.state`.

U metod definovaných pomocí klasické syntaxe tříd se hodnota `this` může „ztratit“ při předávání metody jako zpětného volání události, například metodě `onClick` . Proto v mnoha starších tutoriálech uvidíte vzory jako `this.method.bind(this)` v konstruktoru nebo přímo v JSX, což je dnes považováno za poměrně upovídané.

Typické vzorce vazby v Reactu

V komponentě třídy historicky existovaly čtyři hlavní způsoby, jak zajistit, aby `this` vždy odkazovalo na komponentu při volání z obslužné rutiny události:

  • Usar vážou v metodě výnos, což zajišťuje kontext, ale při každém vykreslení vytváří novou funkci.
  • Udělat vazba v konstruktoru aby se zabránilo opakovanému vytváření funkce, zachování jediné reference.
  • Definujte obslužnou rutinu jako vlastnost třídy s funkcí šipky, s využitím skutečnosti, že šipkové funkce zachycují tento instance.
  • Použití Funkce šipky inline v JSX, přímé předání funkce šipky atributu onclick nebo ekvivalent.

V praxi se možnost deklarace obslužné rutiny jako vlastnosti třídy pomocí šipkové funkce stala nejpohodlnějším vzorem: píšete méně kódu, vyhnete se nutnosti ručního vázání a `this` vždy bez překvapení ukazuje na komponentu.

Funkce šipek v komponentách funkcí

S příchodem funkčních komponent a hooků se React mnohem více spoléhá na šipkové funkce. Většina moderních komponent je implementována jako `const MyComponent = () => { … }` , což činí použití šipkových funkcí přirozeným a konzistentním v celém stromu.

V rámci těchto komponent je běžné kombinovat šipkové funkce s dalšími funkcemi ES6, jako je destrukturování , šablonové literály , ternární operátory , spread a metody polí, jako jsou map , filter a reduce , čímž se vytváří velmi expresivní syntaxe, která vyžaduje dobrou práci s kontextem a neměnností.

V globálním kontextu, jednotlivé objekty a funkce

Abychom pochopili, proč šipkové funkce tolik mění hru, stojí za to se podívat, jak se `this` chová v různých nativních kontextech JavaScriptu, a to jak v prohlížeči, tak v Node.js.

V globálním rozsahu prohlížeče , mimo jakoukoli funkci nebo modul, `this` odkazuje na objekt `window` . To znamená, že jakákoli proměnná deklarovaná s `var` na vyšší úrovni je pod tímto globálním objektem a je přístupná jak podle názvu, tak pomocí `window.name` , což je ve složitých aplikacích považováno za špatný postup kvůli globální kontaminaci.

toto v rámci doslovných objektů

Když definujete objektový literál pomocí tradičních metod, každá metoda obdrží proměnnou `this` , která odkazuje na samotný objekt, když je vyvolána jako `obj.method()` . Toto je standardní způsob, jak přistupovat k vlastnostem na stejné úrovni pomocí `this.property` bez nutnosti mezilehlých proměnných.

Problém nastává, když tyto metody nahradíte šipkovými funkcemi . Protože nemají vlastní `this` , šipková funkce zachytí externí `this`, což je pravděpodobně globální `this` nebo `this` modulu. Výsledkem je, že nebudete moci přistupovat k vlastnostem objektu pomocí `this` v rámci metody , což zcela naruší původní záměr návrhu.

Pokročilé využití Sublime Textu pro rychlou editaci
Související článek:
Pokročilé využití Sublime Textu pro rychlou editaci

Toto je v rámci volných funkcí a striktního režimu

V tradičních, základních funkcích bez objektu příjemce závisí hodnota proměnné `this` na tom, zda je kód v striktním režimu či nikoli. V nestriktním režimu se vrací ke globálnímu objektu , zatímco v striktním režimu je explicitně nastavena na hodnotu `undefined` , aby se zabránilo nebezpečným akcím v globálním prostředí.

Toto chování se drasticky mění, když zapouzdříte svůj kód do ES modulů, moderních bundlerů nebo IIFE, kde se globální rozsah může lišit nebo nemusí být vázán na ` this` obvyklým způsobem, zejména v Node.js , kde hlavní rozsah souboru je rozsah modulu a nikoli globální rozsah.

volání, použití, vazba a jejich vztah k tomuto

JavaScript nabízí tři široce používané metody pro správu kontextu v klasických funkcích: `call` , `apply` a `bind` . Všechny tyto metody umožňují explicitně ovládat hodnotu ` this` při spuštění funkce.

Tyto metody fungují pouze s funkcemi deklarovanými pomocí atributu `function` (nebo ekvivalentů), protože šipkové funkce ignorují jakýkoli pokus o změnu jejich atributu `this`. Proto jsou všechny tři tak užitečné při práci se staršími API, staršími třídami nebo vzory, kde chcete stejnou funkci znovu použít napříč různými objekty.

zavolat a použít: vyvolat s explicitním this

Jak funkce `call` , tak `apply` provedou funkci okamžitě ; jediný rozdíl je ve způsobu předávání argumentů. V obou případech je prvním předávaným parametrem objekt, který má být uvnitř funkce převeden na `this` .

S metodou `call` se následné argumenty zadávají jeden po druhém, zatímco s metodou `apply` se předávají jako pole . To funguje velmi dobře v situacích, kdy již máte seznam argumentů jako kolekci a chcete jej vložit do volání tak, jak je.

bind: vytvoření nové funkce s `this` set

Metoda `bind` neprovede funkci okamžitě; místo toho vytvoří novou funkci s ` this` trvale asociovanou s objektem, který zadáte. Je to jako vytvoření „specializované“ verze originálu, která se bude vždy chovat v daném kontextu.

Tento vzor je velmi běžný pro předávání objektových metod API, která je později volají, například jako zpětná volání událostí, aniž by došlo ke ztrátě původního kontextu. Před popularizací šipkových funkcí byl bind jedním z nejčistších způsobů, jak zajistit, aby metoda třídy nadále ukazovala na správnou instanci.

Proč jsou šipkové funkce ideální pro zpětná volání?

Jedním z důvodů, proč šipkové funkce dobyly ekosystém JavaScriptu, je jejich vhodnost pro asynchronní zpětná volání a funkcionální programování. Při práci s API, jako je setTimeout , setInterval , promises nebo smyčka událostí Node.js, často potřebujete přistupovat k externímu kontextu, aniž by byl zkreslen.

Před verzí ES6 se používaly triky jako uložení `const self = this` nebo `const that = this` před zadáním callback funkce, aby se zajistilo, že se z funkce bude stále odkazovat na správný objekt. Šipkové funkce to činí zbytečným tím, že automaticky zachycují a uchovávají externí `this`.

Funkce se šipkami a smyčka událostí v Node.js

V Node.js , kde se většina zajímavého kódu točí kolem asynchronního I/O (soubory, sítě, časovače), kombinace šipkových funkcí s modelem smyčky událostí a frontami zpětných volání věci značně zjednodušuje. Kdykoli předáte funkci jako obslužnou rutinu `fs.readFile` , HTTP serveru nebo jakékoli operaci libuv, šipkové funkce pomáhají udržovat odkaz na souvislé proměnné a kontext modulu bez překvapení.

Navíc ve frontách mikroúkolů, jako jsou promise nebo process.nextTick , je velmi běžné psát krátké zpětné volání jako then nebo catch se syntaxí šipky, využívající jak implicitní return , tak lexikální this , což kód činí deklarativnějším a expresivnějším.

Kdy byste NEMĚLI používat šipkové funkce?

Ačkoli se šipkové funkce mohou jevit jako magické řešení všech problémů, existují scénáře, ve kterých je jejich použití přímo kontraproduktivní a dokonce generuje chyby, které je obtížné odhalit.

Jedním z nich, možná nejdůležitějším, jsou metody objektů nebo tříd, které potřebují vlastní `this` . Dalším je situace, kdy chcete vytvářet konstruktory nebo používat objektově orientované vzory podporované prototypy a dědičností, kde absence prototypu a vlastního kontextu znamená, že šipkové funkce jednoduše nepasují.

Nepoužívejte šipkové funkce jako objektové metody.

Pokud definujete metodu objektu pomocí šipkové funkce, vnitřní `this` se nebude odkazovat na samotný objekt , ale na kontext, ve kterém byl tento objekt definován. To narušuje očekávání každého, kdo čte kód a má v úmyslu použít `this.property` v rámci metody.

Doporučený způsob psaní metod závislých na `this` je pokračovat v používání klasické syntaxe v literálních objektech nebo deklarovat tyto metody ve standardní formě ve třídách a rezervovat šipkové funkce pro interní zpětná volání, která potřebují `this` zachytit z metody vyšší úrovně.

Nepoužívejte šipkové funkce jako konstruktory.

Šipkové funkce postrádají ` [[Construct]]` , interní mechanismus, který umožňuje volání funkce pomocí `new` . Proto pokus o jejich použití jako konstruktorů povede k chybě ` TypeError` . Také jim chybí vlastní prototyp , takže k instancím nelze přiřadit sdílené metody.

Pokud váš návrh vyžaduje opakovaně použitelné instance se společnými vlastnostmi a metodami, měli byste se rozhodnout pro třídy nebo tradiční konstruktorové funkce a ponechat šipkové funkce pro bezstavovou logiku nebo čistě funkční utility.

Vztah s dalšími moderními funkcemi JavaScriptu

Šipkové funkce se zřídka používají samostatně; téměř vždy jdou ruku v ruce s dalšími funkcemi moderního ECMAScriptu , které také ovlivňují způsob organizace a porozumění kódu. Mezi nejpříbuznější patří `let` a `const` , neměnnost , destrukturalizace a syntaxe rozložení.

Vědět, jak je správně kombinovat, vám umožňuje psát velmi stručné šipkové funkce, které transformují data pomocí metod pole, jako jsou map , filter a reduce , a vždy zachovávají původní stav neporušený, což je v prostředích, jako je React, kde je vzorec neměnnosti normou, klíčové.

Pokročilá úprava a automatizace textu s Notepad++
Související článek:
Pokročilá úprava a automatizace textu s Notepad++

let, const a neměnnost

Zavedení funkcí `let` a `const` umožnilo práci s blokovými obory a neměnnými odkazy. V kombinaci s šipkovými funkcemi je nyní běžnou praxí deklarovat funkce jako ` const myFunction = () => {…}` , což zaručuje, že proměnná obsahující funkci nebude přepsána.

V datových strukturách, jako jsou pole a objekty, je neměnnost podporována použitím metody Object.freeze , když chcete zabránit hlubokým změnám, a použitím operací rozložení a čistých metod, když potřebujete vytvořit upravené kopie namísto změny originálu, což je obzvláště důležité, když vykreslování nebo stav závisí na detekci změn.

Šablonové literály, ternární algoritmy a zkraty

Při vykreslování zpětných volání, například v JSX nebo při konstrukci řetězců HTML, je téměř nevyhnutelné kombinovat šipkové funkce s literály šablon (backticky) a operátory, jako jsou ternární operátory nebo short-circuit evaluation . Tyto operátory umožňují psát velmi expresivní inline podmínky, které se velmi dobře hodí k deklarativnímu stylu šipkových funkcí.

V rámci šablonových literálů jsou výrazy ${…} řešeny se stejným lexikálním rozsahem, který řídí `this` šipkových funkcí, takže je nezbytné mít jasno v tom, které proměnné a jaký kontext se v každé interpolaci používají, aby se předešlo nejednoznačnému chování.

Šipkové funkce v iteracích a kolekcích

Jednou z oblastí, kde šipkové funkce přinesly největší rozdíl, je práce s poli a kolekcemi . Předávání krátkých zpětných volání metodám jako map , filter , find nebo reduce se díky syntaxi šipek stává mnohem čitelnějším.

Například filtrování položek ze seznamu podle kategorie nebo transformace výsledků API do interních datových struktur se stává mnohem deklarativnějším a v kombinaci s destrukturalizací je snadné extrahovat pouze vlastnosti, které potřebujete v rámci parametrů funkce.

mapovat, filtrovat, redukovat a spol.

Typická kombinace je obvykle něco jako list.filter(item => condition).map(item => transformation) , která řetězí několik šipových funkcí v metodách pole. Každá z nich dědí `this` z kontextu, kde je definována, ačkoli ve většině těchto případů se `this` ani nepoužívá, ale spíše se používají explicitní parametry, které posilují funkční styl.

V metodě reduce , kde spravujete akumulátor, který přechází z iterace do iterace, umožňují šipkové funkce vyjádřit operaci reduce velmi stručně, i když je vhodné nepoužívat příliš husté výrazy, pokud chcete, aby kód zůstal srozumitelný pro ostatní vývojáře.

Importy, exporty a moduly

V moderním ekosystému JavaScriptu je téměř veškerý kód organizován do modulů , a to buď pomocí nativní syntaxe importu/exportu , nebo pomocí systémů pro sdružování, které se do tohoto formátu kompilují. V tomto kontextu se šipkové funkce velmi dobře hodí jako opakovaně použitelné funkční jednotky.

Je běžné vidět utility exportované jako ` const myUtil = (…) => {…}` a poté importované do různých souborů. Protože každý modul je ve svém vlastním oboru platnosti, lexikon šipkových funkcí `this` má tendenci být stejný jako lexikon modulu, což není pro většinu čistých utilit relevantní, protože nepotřebují kontext.

Nejlepší postupy s externími moduly a skripty

Při načítání JavaScriptu na HTML stránce je vhodnější jej načíst prostřednictvím externích souborů , než vkládat velké inline bloky. Použití atributu `type="module"` v tagu `<script>` navíc umožňuje moderní syntaxi importu/exportu a jasně indikuje, že soubor je ve výchozím nastavení spuštěn v striktním režimu.

Z hlediska výkonu umožňuje umístění skriptů modulů do sekce `head` s `defer` prohlížeči stáhnout a spustit kód bez blokování vykreslování HTML , čímž se zachovává dobrý uživatelský zážitek. V celém tomto schématu jsou šipkové funkce jednoduše nejpřirozenějším způsobem, jak definovat malé části opakovaně použitelné logiky.

Vkládání a manipulace s DOM pomocí moderního JavaScriptu

Ačkoli se toto téma zaměřuje na funkce `this` a `arrow`, nelze ignorovat roli JavaScriptu v manipulaci s DOMem . Metody jako `getElementById` , `querySelector` , `setAttribute` a úprava stylů zůstávají zásadní, ale dnes se běžně kombinují s callbacky `arrow`, aby reagovaly na události a aktualizovaly rozhraní.

Pracovat s posluchače událostí pomocí element.addEventListener('click', e => {...}) Toto je standardní způsob, jak propojit logiku s interakcemi uživatele. V těchto obslužných rutinách tento Uvnitř funkce arrow to nebude prvek DOM, ale externí kontext, takže pokud potřebujete uzel, budete muset použít samotný parametr události. e.currentTarget o e.target, místo spoléhání se na to jako u starých inline atributů.

Synchronní JavaScript, asynchronní JavaScript a zpětná volání

Další významnou oblastí, kde šipkové funkce hrají roli, je asynchronní programování . JavaScript je jednovláknový a aby se zabránilo blokování rozhraní, deleguje pomalé operace na prohlížeč nebo Node API, které po dokončení volají vaše zpětné volání.

Předávání šipkových funkcí jako zpětných volání pro `setTimeout` , promise , HTTP požadavky nebo přístupy k disku činí kód kompaktnějším a zachovává kontext bez nutnosti dalších alternativ. Při přechodu od vnořených zpětných volání k promise a následně k `async/await` byly šipkové funkce nezbytné pro zajištění čitelnosti datového toku.

Windows jako tenký klient
Související článek:
Windows jako tenký klient: konfigurace vzdálené plochy a zásad relace

Celkově vzato, pochopení toho, jak šipkové funkce lexikálně zachycují `this` , ve kterých případech jsou vaším nejlepším spojencem a ve kterých je nejlepší se i nadále spoléhat na tradiční funkce, spolu se znalostí toho, jak je kombinovat s moduly, metodami polí, neměnností, třídami a smyčkou událostí, vám umožňuje psát skutečně robustní JavaScript a React. V konečném důsledku jde o výběr správného tvaru funkce pro každý kontext, využití jejích syntaktických výhod, aniž by se člověk dostal do hraničních případů, kdy by se její chování `this` mohlo obrátit proti vám. Sdílejte tuto programovací příručku a seznamte se s šipkovými funkcemi JavaScriptu.


Přidat jako preferovaný zdroj v Googlu