Arrow és `this` függvények JavaScriptben: teljes útmutató

  • Az értéke this A JavaScriptben ez attól függ, hogyan hívják meg a függvényt, globális kontextus, objektummetódusok és szigorú módok használatával.
  • A nyílfüggvények nem hoznak létre saját thisEhelyett lexikailag öröklik annak a tartománynak a terminológiáját, ahol definiálták őket, ami számos problémát elkerül a visszahívások során.
  • Ajánlott nyílfüggvényeket használni visszahívásokban és tömbmetódusokban, de kerüljük őket objektummetódusként, konstruktorként vagy DOM eseménykezelőként, amelyek megkövetelik this dinamikus.

A nyíl és a „this” függvények illusztrációja JavaScriptben

Ha már egy ideje JavaScriptben programozol, biztosan felismered a kulcsszót Ez már több fejfájást is okozott nekedÉs mióta a nyílfüggvények megjelentek az ES6-ban, a dolgok még bonyolultabbá váltak... vagy egyszerűbbé, attól függően, hogyan nézzük.

Ebben a cikkben közelebbről megvizsgáljuk, hogyan működik Ez a hagyományos függvényekre és a nyílfüggvényekre vonatkozik.Miért tűnik úgy, mintha néha egy adott objektumra, máskor pedig a globális objektumra mutatna, és milyen helyzetekben van értelme nyílfüggvényeket használni, és mely helyzetekben jobb elkerülni őket?

Que es preciamente this JavaScriptben

A fenntartott szó this Ez egy hivatkozás a végrehajtási kontextusra az aktuálisan végrehajtott függvényről. Más nyelvekkel ellentétben a JavaScriptben a döntés nem a függvény definiálásának helyén, hanem a függvény végrehajtásán alapul. hogyan kell meghívni.

Ez azt jelenti, hogy ugyanazt a függvényt többféleképpen is meghívhatjuk, és mindegyikben this más tárgyra is mutathatEz nem olyasmi, amit közvetlen hozzárendeléssel meg lehet változtatni (nem lehet megtenni this = algo), de befolyásolhatja specifikus mechanizmusokkal, például call, apply y bind.

Továbbá a viselkedésük változó, pl. szigorú mód és nem szigorú módNem szigorú módban, ha egy függvényt "csupasznak" hívsz (objektum nélkül előtte), this Ez általában a globális objektum (a böngészőben, window), míg szigorú módban lehet undefinedEz a megkülönböztetés fontos, amikor különböző forrásokból származó kódpéldákat hasonlítunk össze.

Ez globális kontextusban és normál funkciókban

Böngészőkben, amikor nem tartózkodsz egyetlen modulban vagy függvényben sem, a globális kontextus az objektum. windowés ott this mutass arra a tárgyraVagyis, ha a konzolba beírod a következőket:

console.log(this === window); // true en un entorno de navegador no estricto

Egy „klasszikus” módon deklarált függvényen belül (normál függvény) a következő érték this Attól függ, hogy minek nevezik azt a függvényt.Ha előzetes objektum nélkül hívod meg, nem szigorú módban this Általában a globálisról van szó, és szigorúan véve az is lesz, undefinedEzért van az, hogy néha, amikor kódot helyezünk át egyik webhelyről a másikra, Ez már nem az, amire számítottál..

Ez normál függvényekkel definiált objektummetódusokban van

Amikor egy metódust definiálsz egy objektumon a hagyományos szintaxis használatával, this a metóduson belül magára az objektumra való hivatkozás amelyből az adott metódust meghívták.

Például, ha van valami ilyesmid:

const obj = {
  speak() {
    console.log(this);
  }
};
obj.speak();

A hívás obj.speak() teszi this belül speak légy az egyetlen objEz az a viselkedés, amit az emberek általában intuitíven elvárnak: a metódus az objektum „nevében” beszél.

Ha a rövidített szintaxis helyett egy klasszikus függvényt használsz, a hatás ugyanaz, mert A kulcs abban rejlik, hogyan hívjuk meg a metódustNem számít, hogy a metódus rövidítését vagy a kulcsszót használtad. function a tárgy belsejében.

Ez nyílfüggvényekkel definiált metódusokban

A dolgok megváltoznak, ha a metódust egy nyílfüggvénnyel definiálod. Valami ilyesmi:

const obj2 = {
  speak: () => {
    console.log(this);
  }
};
obj2.speak();

Ebben az esetben a végrehajtás során obj2.speak() azt látni fogod this Ez már nem az obj2de a külső lexikai kontextus arra az objektumra, ami egy klasszikus böngészőszkriptben általában a globális objektum window.

Ez elsőre zavarba ejtő, mivel azt várod, hogy az objektum metódusa magára az objektumra mutasson. Azonban a nyílfüggvények nem hoznak létre saját thisŐk öröklik az értékét this abban a hatókörben, ahol definiálták őket. Ha a hatókör globális, akkor a globális hatókört öröklik; ha egy másik, akkor azt a másik hatókört öröklik.

Ezért a modern dokumentációban gyakran ismételt ajánlás a következő: Ne használj nyílfüggvényeket objektummetódusként amikor szükséged van rá this célozd meg azt a tárgyat.

Lexikai hatókör this nyílfüggvények

A normál függvények és a nyílfüggvények közötti legfontosabb különbség az utóbbiak lexikai kapcsolattal rendelkezik a következőhöz: thisEgyszerűen fogalmazva: nem ők döntik el, this nem akkor, amikor felhívják egymást, hanem amikor teremt.

Képzeld el ezt a példát:

const obj3 = {
  speak() {
    (() => {
      console.log(this);
    })();
  }
};
obj3.speak();

Itt úgy tűnhet, hogy belülről speak végrehajtunk egy nyílfüggvényt, Ennek "vissza kell állnia" a globális szintreDe pont az ellenkezője történik: a nyílfüggvény rögzíti a this a körülötte lévő funkciórólami ebben az esetben a módszer speak hivatkozva obj3.speak()Ezért a this A konzolon látható az, amelyik innen származik. obj3.

Értem a nyílfüggvényeknek nincs sajátjuk thishanem inkább a közvetlen környezetüket használják fel újraEz hihetetlenül hasznos beágyazott visszahívásokban, időzítőkben, ígéretekben és bárhol máshol, ahol a klasszikus függvényekkel meg kellett küzdeni .bind vagy olyan trükkökkel, mint const that = this;.

Gyakorlati példák az elvesztésére és megőrzésére this

A JavaScript egyik klasszikus problémája, hogy amikor egy függvényt egy metóduson belül definiálunk, elveszíted a hivatkozást this ami a tárgyra mutatott és végül a globálisnál vagy a undefined.

Vegyük a tipikus esetet, amikor a setTimeout egy hagyományos függvénnyel rendelkező objektum metódusán belül:

const persona = {
  nombre: 'Agustin',
  decirNombre: function() {
    setTimeout(function() {
      console.log(this.nombre);
    }, 3000);
  }
};
persona.decirNombre(); // Muestra undefined

Itt ezt a függvényen belül adjuk át a setTimeout Ez már nem a tárgy personaEz a visszahívó függvény globális kontextusban fut (egy böngészőben, window), így this.nombre Megpróbál egy globális tulajdonságot beolvasni, ami nem létezik, és végül a következő eredményt adja: undefined.

Mielőtt a nyílfüggvények léteztek volna, egy gyakori megoldás az érték tárolása volt. this egy segédváltozóban hogy "behúzd" a függvénybe:

const persona = {
  nombre: 'Agustin',
  decirNombre: function() {
    let that = this; // aquí this es persona
    setTimeout(function() {
      console.log(that.nombre);
    }, 3000);
  }
};

Ennek a változónak köszönhetően megmarad az objektumra való helyes hivatkozás. De ez egy kissé csúnya és ismétlődő trükk. Nyílfüggvényekkel ez a probléma jelentősen leegyszerűsödik:

const persona = {
  nombre: 'Agustin',
  decirNombre: function() {
    setTimeout(() => {
      console.log(this.nombre);
    }, 3000);
  }
};

Itt a nyílfüggvény nem hoz létre saját this, így örökli a this a módszer decirNombremelyik a tárgy personaAz eredmény: Az „Agustin” helyesen jelenik meg köztes változók vagy .bind.

hívás, alkalmazás és kötés: az értékének szabályozása this

A kontextus metódushívással történő „természetes” beállításán túl a JavaScript eszközöket biztosít számunkra a következőkhöz: erőltesse az értékét this normál funkciókban: call, apply y bind.

Mód call() y apply() Azonnal meghívják a függvényt, lehetővé téve a használni kívánt objektum átadását. this. A különbség az call egyesével fogadja az argumentumokat, miközben apply Egy tömbben fogadják őket. bind(), ehelyett egy új függvényt ad vissza a következővel: this „csatolt” az Ön által jelzett értékhezhogy később, amikor neked megfelel, felhívhasd.

Nyílfüggvények esetén azonban ezek a metódusok nem hasznosak a változtatáshoz this mert az értéke lexikailag összekapcsolódik. Te tudod használni call, apply o bind argumentumok átadására, de a nyílfüggvények kontextusának módosítására nem, ami egy nagyon fontos különbség a hagyományos függvényekhez képest.

A nyílfüggvények alapvető szintaxisa

A viselkedésén túl thisA nyílfüggvények biztosítják a kompaktabb és kifejezőbb szintaxis sok helyzetben. Az általános forma a következő:

(arg1, arg2, ..., argN) => expresion

Ez az űrlap automatikusan visszaadja a nyíltól jobbra lévő kifejezés eredményét, tehát Nem kell leírni a szót return amikor csak egyetlen egyszerű kifejezésed van.

Néhány gyakori szintaxispont:

  • Paraméterek nélkül:
    () => 42 vagy akár _ => 42 ha nem érdekel az argumentum neve.
  • Egyetlen paraméterrel:
    A zárójelek használata opcionális; írhat x => x * 2 o (x) => x * 2.
  • Több paraméterrel:
    Zárójelek használata kötelező: (x, y) => x + y.

Amikor több utasításra van szükséged, használhatod a blokk test kulcsokkal:

const sumar = (x, y) => {
  const resultado = x + y;
  return resultado;
};

Ebben az esetben, mivel vannak kulcsok, Nincs többé implicit hozam; ha nem teszed be returna függvény visszaadja undefinedEz mind a nyílfüggvényekre, mind a hagyományos függvényekre vonatkozik.

Literál objektumok visszaadása nyílfüggvényekkel

Van egy apró, de nagyon gyakori szintaktikai részlet: amikor egy nyílfüggvény egy szó szerinti tárgy közvetlenülZárójelek közé kell tenni, hogy az értelmező ne nézze össze blokkal.

Például:

x => ({ y: x })

Zárójelek nélkül a JavaScript a kapcsos zárójeleket a függvény törzsének kezdeteként értelmezné, nem pedig objektumként. Ez egy egyszerű trükk, de sok buta hibát okoz, ha elfelejtjük.

Nyílfüggvények: névtelenek és prototípus nélküliek

A nyílfüggvények a következők: szintaktikailag anonimNincsenek rendes nevük, ami némileg bonyolíthatja a dolgokat. hibakeresési és hibaüzenetekmert a nyomkövetésben nem látod közvetlenül a függvényazonosítót, kivéve, ha egy felismerhető nevű konstanshoz rendelted.

Ezenkívül a nyíl funkciók Nincs saját tulajdonuk prototype és nem használhatók építőipari vállalatkéntHa megpróbálod megidézni őket newHibát fogsz kapni. Objektumok konstruktorok vagy osztályok használatával történő létrehozásához továbbra is normál függvényeket vagy szintaxist kell használnod. class.

Egy másik következmény, hogy Nem alkalmasak olyan mintákhoz, amelyek belső önhivatkozást igényelnek., például bizonyos rekurziós formák vagy eseménykezelők, amelyeknek le kell iratkozniuk a this vagy a függvény saját neve.

Ahol a nyílfunkciók ragyognak

A nyílfüggvények nagy erőssége pontosan az, hogy lexikai összekapcsolása thisIdeálisak olyan helyzetekben, amikor azt szeretnéd, hogy a visszahívás, amit átadsz egy másik függvénynek, fenntartsa a this a környező területről.

Például egy olyan objektumban, amelynek metódusa elindít egy időzítőt, és folyamatosan hozzá kell férnie magának az objektumnak a tulajdonságait használva this:

const contador = {
  id: 42,
  iniciar() {
    setTimeout(() => {
      console.log(this.id); // this es contador
    }, 1000);
  }
};

Az ES5-ben gyakori volt, hogy be kellett tenni .bind(this) a visszahíváshoz vagy mentéshez this egy másik változóban. Nyílfüggvényekkel A kód tisztábbá és a tényleges szándékhoz közelebb állóvá válik..

Nagyon praktikusak tömbmetódusokkal is, mint például map, filter, reduce és a társaság, mert szintaktikai zaj csökkentése amikor a függvénylogika rövid:

const numeros = [1, 2, 3];
const dobles = numeros.map(n => n * 2);

Takarékosan használva ezek a kompakt formák megkönnyítik az adatfolyam követését egy pillantással.

Mikor kerüljük a nyílfüggvényeket

Bár a nyílfüggvények nagyon hasznosak, nem helyettesítik a hagyományos függvényeket. Számos egyértelmű eset létezik, amikor A legjobb, ha nem használjuk őket.:

  • Objektummetódusok, amelyek a következőktől függenek: this:
    Ha egy metódust úgy definiálsz, hogy saltos: () => { this.vidas--; } egy tárgy belsejében gato, this Nem a macskára fog mutatni, hanem a külső környezetre, és az ingatlan nem a várt módon frissül.
  • DOM eseményvisszahívások, amelyekhez szükség van egy this dinamikus:
    Egy olyan kezelőben, mint boton.addEventListener('click', () => { this.classList.toggle('on'); });, this Nem a megnyomott gomb, hanem a magasabb kontextus fogja valószínűleg típushibát okozni.
  • Építők vagy függvények, amelyekhez szükség van prototype:
    Mivel nem használható együtt newA nyílfüggvények nem alkalmasak példányok létrehozására vagy prototípus-alapú minták létrehozására.

Mindezen esetekben egy A normál funkció továbbra is a megfelelő eszköz mert ezt lehetővé teszi this Dinamikusan kapcsolódik a függvény meghívásának módjához.

Ha megszokod, hogy tudatosan választasz a normál funkció és a nyílfunkció között attól függően, hogy mire van szükséged this és a kontextusból kiindulva, A kódod kiszámíthatóbb és olvashatóbb lesz. bárki számára, aki később megtartja.

Végső soron annak megértése, hogy mi az értéke this JavaScriptben, és hogyan öröklik a nyílfüggvények ezt az értéket A váratlan eredményekkel való küzdelmek megszüntetésének, az ES6 szintaktikai előnyeinek kihasználásának, valamint olyan metódusok, visszahívások és eseménykezelők írásának kulcsa, amelyek pontosan azt teszik, amire gondoltál, az a lexikai hatókör megértése, ahol ezek létrejönnek.