Bemästra pilen och dessa funktioner i JavaScript

Senaste uppdateringen: 28/01/2026
Författare: Isaac
  • Pilfunktioner förenklar syntaxen och fångar lexiskt värdet av `this`, till skillnad från vanliga funktioner.
  • JavaScript avgör `detta` i klassiska funktioner med fyra regler: explicit bindning, implicit bindning, bindning med `new` och standardbindning.
  • Pilfunktioner är idealiska för återanrop och asynkron kod, men bör inte användas som metoder som är beroende av `detta` eller som konstruktorer.
  • Att behärska den kombinerade användningen av normala funktioner, pilfunktioner och tekniker som call, apply och bind är nyckeln till att skriva modern och robust JavaScript.

Skillnader mellan "hej världen" i Python, JavaScript, Java, C, C++, Go, Swift, R, Ruby, Rust, VBA, C#, COBOL och Fortran

Att bemästra pilfunktioner och beteendet hos `this` i JavaScript är revolutionerande för dina utvecklingsfärdigheter. Dessa två ämnen kan verka förvirrande till en början, men när du väl förstår dem kommer du att börja lägga märke till buggar som du tidigare missat, skriva tydligare kod och ha mindre problem med kontext.

I den här artikeln ska vi tydligt och enkelt titta på hur man skriver pilfunktioner, hur de skiljer sig från vanliga funktioner och hur detta påverkar `this` . Vi kommer också att gå igenom viktiga begrepp som `call`, `apply`, `bind`, användningen av `new`, de olika typerna av `this`-bindning, hur den beter sig i klasser, händelser, callbacks, miljöer som React och Node.js, och när det är vettigt att använda eller undvika pilfunktioner.

Grundläggande syntax för pilfunktioner

En pilfunktion skrivs med symbolen => och är alltid ett funktionsuttryck , det vill säga den deklareras inte med funktionsnamn(), utan tilldelas en variabel eller egenskap.

Den allmänna formen är ungefär så här: const myFunction = (param1, param2) => { /* code */ } . Precis som en klassisk anonym funktion, men genom att ersätta ordet function med pilen => och behålla parenteserna för parametrarna och klammerparenteserna för brödtexten.

Det är viktigt att förstå att pilfunktioner inte är funktionsdeklarationer : du kan inte använda dem innan du definierar dem eftersom de inte är hoistade (det finns ingen hoisting på samma sätt som med `function name()`). De beter sig alltid som uttryck som utvärderas när tolken passerar över den raden.

Syntaxgenvägar: kortare versioner av pilfunktioner

När koden inuti funktionen är mycket enkel, möjliggör pilfunktioner en mer kompakt och läsbar syntax . Om brödtexten bara har en sats och den satsen är en retursats, kan flera saker utelämnas:

  • Ordet kan tas bort fungera (Vi har faktiskt redan tagit bort den.)
  • De kan tas bort Nycklar {}.
  • Ordet kan utelämnas avkastning, med hjälp av implicit retur.

Till exempel, istället för att skriva en summa som `const sum = function(a, b) { return a + b; }` , kan du med arrow lämna den som `const sum = (a, b) => a + b;` . Resultatet är detsamma, men koden är kortare och läses bättre, särskilt i callbacks och arraymetoder.

Parametrar i pilfunktioner

Reglerna för parametrar ändras något med syntaxen, och det är viktigt att förstå dem eftersom dumma misstag är vanliga i början:

  • En enda parameterDu kan ta bort parenteserna och skriva något i stil med namn => `Hej ${namn}`Det är helt giltigt och mycket vanligt.
  • NollparametrarParenteserna är obligatoriska där, eftersom du behöver något före pilen: () => console.log('Inga parametrar').
  • Två eller fler parametrarDu behöver även parenteser, till exempel (a, b, c) => a * b * c.

I samtliga fall, om funktionskroppen reduceras till ett enkelt uttryck, kan du dra nytta av den implicita return och eliminera klammerparenteser och return , vilket är mycket praktiskt i metoder som map, filter, reduce eller i små transformationsfunktioner.

Implicit retur och objektretur

När arrow-funktionen har ett enda uttryck returneras värdet för det uttrycket automatiskt om du inte använder klammerparenteser. Men när du vill returnera ett literalobjekt finns det ett viktigt knep: du måste radbryta objektet inom parenteser.

Om du skriver något i stil med `const crearUsuario = (nombre, edad) => { nombre: nombre, edad: edad }` tolkar JavaScript klammerparenteserna som funktionens innehåll, inte som ett objekt att returnera, så det returnerar ingenting (odefinierat). För att det ska fungera måste du skriva `const crearUsuario = (nombre, edad) => ({ nombre, edad })`.

Kort sagt, när din arrow-funktion behöver returnera ett objekt på en enda rad , radbryt det objektet inom parenteser så att motorn förstår att det är det returnerade värdet och inte ett kodblock.

Viktiga skillnader mellan normala funktioner och pilfunktioner

Utöver syntaxen är det som verkligen är viktigt för daglig användning att pilfunktioner inte beter sig på samma sätt som "normala" funktioner i flera kritiska aspekter : `detta`, argument, användning som metoder, konstruktorer, etc.

Hantera detta i vanliga funktioner

I en klassisk funktion beror värdet på `this` på hur funktionen anropas , inte var den definieras. Denna distinktion är källan till mycket av förvirringen.

  • Om du anropar en funktion som obj.metod()Inom den metoden pekar detta på obj (implicit bindning).
  • Om du anropar en enda funktion, minFunktion(), utan ett objekt framför, i icke-strikt läge kommer detta att vara det globala objektet (fönstret i webbläsaren) och i strict läge kommer det att vara odefinierat.
  • Om du använder ny MinFunktion(), då inom MyFunction, kommer detta att vara det nya objektet som skapas (binder med new).
  • Om du använder anropa, ansöka eller bindaDu kan explicit ange vilket objekt du vill att detta ska vara.

Denna dynamiska natur gör `detta` mycket kraftfullt, men också mycket enkelt att bryta sig in i återanrop och asynkron kod om du inte är tydlig med var varje funktion anropas ifrån.

  Metoder för att kopiera information från en persons konto till en annan i hemmet windows 10

Lexikal hantering av "detta" i pilfunktioner

Pilfunktioner ändrar reglerna helt: de har inte sin egen `detta` . Istället för att få en ny `detta` beroende på deras namn, fångar de `detta` för den miljö där de skapades, vilket kallas en lexikal `detta`.

Det här betyder att inom en pilfunktion är `this` exakt samma `this` som fanns på den plats där funktionen definierades. Den påverkas inte av hur den anropas eller av `call/apply/bind`. Den här funktionen är ovärderlig för att hantera arraymetoder, `setTimeout`, `setInterval`, promises och alla situationer där du tidigare var tvungen att jonglera med `self = this` eller `bind`.

De fyra huvudreglerna för `detta` i JavaScript

För att helt förstå varför pilfunktioner är så användbara är det viktigt att förstå hur JavaScript bestämmer värdet på `this` i vanliga funktioner . Det finns fyra grundläggande regler, tillämpade i denna prioritetsordning:

  1. Explicit bindning: när du använder call, apply eller bind för att åtgärda detta.
  2. Implicit bindning: när du anropar en metod som en egenskap för ett objekt (obj.method()).
  3. Bindning med nytt: när du anropar en funktion med new, och omvandlar den till en konstruktor.
  4. Standardbindning: när inget av ovanstående gäller (globalt eller odefinierat beroende på läget).

Pilfunktioner "kringgår" detta system: de deltar inte i dessa regler eftersom de aldrig skapar sin egen `detta` . De ärver helt enkelt den som finns i den omgivande koden.

Explicit bindning: anropa, tillämpa och binda

Normala funktioner låter dig tvinga fram värdet på `this` med hjälp av tre välkända metoder: `call`, `apply` och `bind` . Dessa är grundläggande för att förstå den klassiska modellen och för att jämföra den med beteendet hos pilfunktioner.

anropa och tillämpa: kör med anpassad `detta`

Både `call` och `apply` används för att omedelbart anropa en funktion med en specifik `this` . Skillnaden ligger i hur du skickar argumenten: `call` tar emot dem ett efter ett, medan `apply` tar emot en array.

Om du till exempel har en funktion som anropar `this.name` kan du anropa den funktionen med olika objekt och återanvända logiken. Detta är mycket vanligt när du vill dela funktioner mellan objekt utan att duplicera kod.

bind: skapa en ny funktion med `this`

`bind` fungerar annorlunda: istället för att köras omedelbart returnerar den en ny funktion där `this` är "kopplad" till objektet du skickar den till. Dessutom kan du ange argument i förväg (delvis tillämpning), så den resulterande funktionen kommer redan med några fördefinierade parametrar.

Det är mycket användbart när du vill skicka metoder som återanrop utan att förlora deras ursprungliga kontext , till exempel i händelselyssnare eller i setInterval, där `this` ofta är trasig.

En viktig detalj är att en funktion som redan är bunden med `bind` ignorerar efterföljande försök att ändra `this` med `call` eller `apply` . Bindningen är permanent för den härledda funktionen.

Implicit bindning och förlust av kontext

Implicit bindning sker när du anropar en funktion som en metod för ett objekt ; det vill säga, det finns något till vänster om punkten. I så fall blir "detta" det objektet.

Om du till exempel har ett restaurangobjekt med metoderna welcomeGuest och cookPizza, och du använder restaurant.welcomeGuest() , pekar metoden på själva restaurangen, vilket gör att du kan komma åt egenskaper som namn eller plats.

Problemet börjar när du separerar metoden från objektet , till exempel genom att skicka det som en återanrop: `setInterval(this.tick, 1000)`. När timern körs finns det inte längre ett objekt till vänster om tick-koden. Den implicita bindningen går förlorad och standardbindningen tar över, vilket gör `this` global eller odefinierad, och din kod misslyckas.

Den klassiska lösningen var att använda `bind(this) ` eller lagra en referens som `const self = this`. Numera är pilfunktioner en perfekt lösning för att lösa denna förlust av kontext , eftersom de ärver det yttre `this` och inte modifierar det ens när de skickas som återanrop.

Konstruktörer, nya och detta

När du anropar en funktion med new , gör JavaScript automatiskt flera saker för att behandla den som en konstruktor:

  • Skapa ett nytt tomt objekt.
  • Vincula Detta är ett nytt objekt inom funktionen.
  • Anpassa prototypen för det nya objektet till konstruktorns prototyp.
  • Returnera objektet, såvida du inte uttryckligen returnerar ett annat objekt.

Tack vare detta tillåter en konstruktor som `function Persona(nombre) { this.nombre = nombre; }` dig att göra `const p = new Persona('Ana');` och ha ett objekt med egenskapen `nombre`. Inuti konstruktorn refererar `this` till den nyskapade instansen.

Detta mönster används också för att designa mer komplexa strukturer, såsom ett bankkonto med insättnings- och uttagsmetoder eller ett fordon med körmetoder och egenskaper som årsmodell och modell. I alla dessa fall är "detta" den konkreta instansen du arbetar med.

Mycket viktigt: pilfunktioner kan inte användas som konstruktorer . De stöder inte användningen av `new`, och om du försöker får du ett felmeddelande. Eftersom de inte har någon egen `this` eller `prototype` passar de inte in i den här modellen.

Standardbindning och strikt läge

När varken explicit, implicit eller ny bindning gäller, återgår JavaScript till standardbindningen :

  • I icke-strikt läge, Detta pekar mot det globala objektet (fönster i webbläsaren, globalt i Node.js).
  • I strikt läge ('använd strikt'), Detta är odefinierat i en normal funktion som kallas "en barbacka".

Denna ändring av strict-läge är mycket fördelaktig eftersom den förhindrar att du av misstag ändrar det globala objektet när du trodde att du arbetade med en annan kontext. Många vanliga fel med `this` uppstår när du aktiverar 'use strict' just för att de slutar fungera korrekt och snabbt misslyckas.

  Så här installerar du ytterligare språk i Windows 11 steg för steg

En annan viktig detalj är att i webbläsarens globala miljö blir variabler som deklareras med `var` egenskaper för det globala objektet . Så om du deklarerar `var globalName = 'User'` kan du komma åt `window.globalName`. Detta blandas med `this` i icke-strikta funktioner och leder till märkligt (och ibland farligt) beteende.

Arrow fungerar som en "game changer" för detta

Den stora fördelen med pilfunktioner är att de inte skapar en ny `this` . Istället fångar de `this` för det scope där de skapas. Enkelt uttryckt: `this` inuti en pilfunktion är samma `this` som utanför.

Detta löser många klassiska problem där kontext förlorades, till exempel i forEach-anrop, setTimeout, lyssnare och promises. Det finns inte längre något behov av att binda till varje intern återanrop eller att bära runt mellanliggande variabler som self eller that för att bevara kontext.

Ett mycket typiskt exempel är att iterera genom en array av medlemmar inom ett teamobjekt. Om du använder en vanlig funktion inuti `forEach`, bryts `this` och pekar inte längre på teamobjektet. Om du använder en pilfunktion istället, behåller `this` värdet för den yttre metoden , så att du kan läsa `this.name` utan några överraskningar.

Global kontext, objektmetoder och pilfunktioner

Pilfunktioner beter sig olika beroende på vilket sammanhang de definieras i :

  • Om de definieras i det globala omfånget ärver de detta globala objekt (fönster- eller modulobjekt beroende på miljön).
  • Om de är definierade inom en normal metodDe ärver `detta` från den metoden, vilket normalt sett är objektet som anropade den.
  • Om du lägger en pil direkt som en metod för ett objekt (myObj.method = () => {}), Så här får man inte objektetmen den externa denna (global eller modulens).

Den sista punkten är avgörande: det är inte en bra idé att använda pilfunktioner som objektmetoder när du är beroende av `this` för att komma åt objektets egenskaper . I dessa fall är det att föredra att använda klassisk funktionssyntax inom metoden, så att `this` är objektet.

Däremot är det bra att använda kapslade pilfunktioner inuti vanliga metoder när du vill ha återanrop som respekterar `detta` för den metoden (till exempel i `forEach`, `map`, `setTimeout`...).

ES6-klasser, this och pilfunktioner

ES6-klasser är inte mycket mer än syntaktiskt socker ovanpå prototypen och konstruktorsystemet , men de hjälper till att strukturera koden bättre. Inom en klass beter sig konstruktorn som en traditionell funktionskonstruktor: `detta` pekar på den nyskapade instansen.

Metoder definierade som `myMethod() { … }` använder också `this` som instans när de anropas från objektet. Men om du extraherar metoden och lagrar den i en variabel utan bindning, kommer du att förlora kontexten igen, precis som med alla andra normala funktioner.

En mycket populär strategi är att definiera vissa klassmetoder som egenskaper med hjälp av `arrow function` , till exempel `getInfoArrow = () => { … }`. Dessa metoder är "bundna" till instansen från det ögonblick den skapas, så även om du skickar dem som återanrop eller tar dem ur sitt sammanhang, kommer `this` fortfarande att peka korrekt på objektet . Detta används i stor utsträckning i ramverk som React (med klasskomponenter) för att undvika att behöva binda varje händelsehanterare i konstruktorn.

DOM-händelser, återanrop och typiska problem med `this`

I webbläsaren, när du lägger till en händelselyssnare med `addEventListener` och skickar en vanlig funktion, pekar `this` inuti hanteraren på DOM-elementet som utlöste händelsen . Detta är ibland användbart, men andra gånger bryter det kontexten för din klass eller ditt objekt.

Om du till exempel använder `this.element.addEventListener('click', this.handleClick)` i en Button-klass, kommer `this` inom `handleClick` att vara DOM-elementet när händelsen utlöses, inte klassinstansen. För att åtgärda detta har du tre vanliga alternativ:

  • Tillämpa binda (detta) när man registrerar lyssnaren.
  • Skicka en pilfunktion som anropar this.handleClick() och ärver därmed this från instansen.
  • Definiera handleClick som en egenskap med en pilfunktion i klassen.

I array-återanrop (map, filter, forEach, etc.) händer något liknande: om du skickar en metod utan en bindning kan du förlora kontext. Återigen är arrow-funktioner mycket praktiska för att skriva interna återanrop som ser lämplig `this` utan att behöva binda manuellt.

Asynkrona operationer, löften och asynkron/vänta

Med async/await bevaras värdet av detta ganska naturligt inom den asynkrona metoden, så länge du använder vanliga funktioner i klassmetoden.

Men när du kedjar löften med `then` och `catch`, och använder vanliga funktioner inom dessa metoder, riskerar du att förlora attributet `this` för instansen. Det är därför det är så vanligt att skriva `.then(data => this.process(data))` och `.catch(error => this.handleError(error))` : pilfunktionerna säkerställer att `this` fortsätter att peka på det ursprungliga objektet.

Kort sagt, i modern asynkron kod är pilfunktioner standardverktyget för att upprätthålla kontext utan att behöva kedjebinda överallt.

När är det lämpligt att använda pilfunktioner

Pilfunktioner lyser särskilt i dessa fall:

  • Korta återuppringningar i arraymetoder, löften, timers, etc.
  • Små och enkla funktioner där du prioriterar korthet framför möjligheten att återanvända detta.
  • Situationer där Vill du att detta ska förbli den från den yttre miljön?, till exempel inom en klass eller objektmetod.
  • Klasskomponenter i React och liknande bibliotek, för undvik att behöva binda i konstruktorn för varje hanterare.
  Allt du behöver veta om vem som skriver till dig på Tellonym

Dessutom, i mer funktionell programmering (funktionskomposition, härdning, datatransformationer) gör pilfunktioner koden mycket mer läsbar och uttrycksfull, eftersom de gynnar rena och korta funktioner utan att behöva namnge dem.

När du INTE ska använda pilfunktioner

Det finns också tydliga scenarier där det inte är en bra idé att använda pilfunktioner och en klassisk funktion är att föredra:

  • Objektmetoder som är beroende av `this` för att komma åt objektets egenskaper. Om du definierar metoden som `arrow`, kommer `this` inte att vara objektet, utan den externa kontexten.
  • ByggarePilfunktioner kan inte användas med new, så de är inte användbara för att skapa instanser.
  • Funktioner som kräver arguments-objektet Pilfunktioner har inga egna argument; om du behöver dem kan du använda en vanlig funktion eller restparametrar (…args).
  • Rena verktyg eller hjälpmedel kontextoberoende

Nyttofunktioner (formatCurrency, calculateTax, små matematiska operationer) bör inte vara beroende av `this` . I dessa fall är det viktigt att de är rena, lätta att testa och inte har några biverkningar. Du kan skriva dem med `function` eller `arrow`, men undvik att förlita dig på `this` alls.

I funktionella programmeringsmönster rekommenderas det också att funktioner inte är kontextberoende. Ju mindre du använder `detta` i den här typen av kod, desto mer förutsägbar och sammansättningsbar blir din kodbas.

Detta i moderna miljöer: React och Node.js

I React med klasskomponenter är användningen av `this` avgörande för att hantera state och props . Händelsehanterare behöver åtkomst till `this.setState` och komponentens egenskaper. Om du inte binder eller använder pilfunktioner för dessa hanterare kommer du att stöta på `this undefined`-fel så fort användaren klickar.

Därför kommer du i många projekt att se mönster som handleChange = (event) => { … } och onClick={this.handleChange} . Dessa pilfunktioner, definierade som klassegenskaper, är automatiskt bundna till instansen , vilket undviker ytterligare bindningar i konstruktorn och minskar risken för kontextfel.

I Node.js är beteendet för `this` på modulnivå inte detsamma som i webbläsaren . På filnivå pekar `this` vanligtvis på `module.exports` (i CommonJS) eller är odefinierat i ES-moduler, istället för det globala objektet. Detta påverkar hur du förstår `this` när du skriver återanvändbara bibliotek och moduler.

I vilket fall som helst förblir regeln densamma: pilfunktioner ärver egenskapen `this` från miljön där de definieras . I Node kommer det att vara modulen eller klassen du befinner dig i, vilket dikterar hur du designar dina API:er och hur du exponerar metoder för andra filer.

Använda JavaScript i miljöer som Appsmith

På plattformar med låg/ingen kod som Appsmith kan du skriva JavaScript i nästan vilken widget-egenskap som helst (text, färg, synlig, inaktiverad, etc.) med hjälp av uttryck inom klammerparenteser {{ }}. Dessa uttryck utvärderas och returnerar alltid ett värde: en sträng, ett tal, ett booleskt värde, ett objekt, etc.

Du kan också definiera reguljära funktioner, uttryck och pilfunktioner inom JSObjects , vilka är block av JavaScript-kod med ett `export default { … }`. Det är viktigt att notera att du på den översta nivån av ett JSObject definierar egenskaper och metoder som kommaseparerade nyckel-värde-par, och att attributet `this` för dessa metoder beter sig beroende på om de är reguljära funktioner eller pilfunktioner.

Som en god praxis använder JSObjects vanligtvis vanliga funktioner som huvudmetoder (för att undvika förvirring med `this`) och kapslade pilfunktioner inom dessa metoder som återanrop för filter, kartor, reduktioner etc. Detta mönster låter dig dra nytta av den kompakta syntaxen för pilar utan att komplicera kontexthanteringen.

Bästa praxis för att bemästra detta och pilfunktioner

För att få ut det mesta av dessa verktyg utan att bli galen finns det ett antal riktlinjer som är värda att lära sig:

  • Var tydlig med sammanhangetOm du är osäker, använd bind- eller arrow-funktionerna för att tydliggöra vilken `this` du vill använda.
  • Använd pilfunktioner för återanrop nästan alltid, särskilt i asynkron kod och arraymetoder, för att undvika att förlora det yttre `detta`.
  • Blanda inte stilar i onödanOm du använder arrow-metoder för hanterare i en klass, behåll det mönstret i hela komponenten för konsekvens.
  • Aktivera 'använd strikt' eller använd miljöer som redan tillämpar strict-läge så att fel med detta utlöses tidigare.
  • Undvik att förlita sig på `detta` för nyttofunktionerJu renare de är, desto lättare är de att testa och återanvända.

En gedigen förståelse för hur och när man använder pilfunktioner, och vad deras lexikala beteende innebär , tillsammans med de bindande reglerna för vanliga funktioner, sätter dig i en mycket starkare position för att skriva modern JavaScript. Med övning kommer du att sluta se "detta" som en förrädisk fiende och istället se det som ett kraftfullt verktyg som du enkelt kan bemästra i alla sammanhang, från webbläsaren till Node.js eller ramverk som React.