Pijlfuncties en het sleutelwoord `this` in JavaScript

Laatste update: 02/10/2026
Auteur: C Bronpad
  • Pijlfuncties bieden een beknopte syntaxis en leggen functionaliteit vast. this lexicaal vanuit hun omringende context, in plaats van hun eigen binding te creëren.
  • De waarde van this Bij reguliere functies hangt het af van hoe ze worden aangeroepen, wat van invloed is op functies, methoden, constructors, klassen en callbacks.
  • Pijlfuncties zijn ideaal voor callbacks en arraymethoden, maar een slechte keuze voor objectmethoden, DOM-gebeurtenishandlers en constructors.
  • Begrijpen wanneer this Het onderscheid tussen dynamische en lexicale functies is essentieel om subtiele fouten te voorkomen en om te kiezen tussen pijl- en traditionele functies.

Pijlfuncties en 'this' in JavaScript

Als je ooit hebt ingelogd this Je bent niet de enige die verschillende JavaScript-functies heeft gebruikt en daarbij zeer uiteenlopende resultaten heeft gekregen. Veel ontwikkelaars komen situaties tegen waarin een methode het verwachte object afdrukt, maar een pijlfunctie iets anders afdrukt. windowEn plotseling wijst een geneste pijl op "magische wijze" terug naar het omringende object. Begrijpen waarom dat gebeurt, is de sleutel tot het schrijven van voorspelbare, foutloze code.

Pijlfuncties en de this De sleutelwoordvorm is een van de belangrijkste (en meest misbegrepen) combinaties in modern JavaScript. Pijlfuncties lijken slechts een kortere syntaxis, maar onder de motorkap veranderen ze hoe... this We bespreken hoe callbacks worden afgehandeld, hoe ze zich gedragen en zelfs wanneer je ze wel of niet als methoden moet gebruiken. We nemen alles stap voor stap door, van syntax tot uitvoeringscontext, in begrijpelijke taal en met veel praktische voorbeelden.

Syntaxis voor pijlfuncties zonder de verwarring

Pijlfuncties zijn functie-uitdrukkingen die geschreven zijn met de => syntaxis in plaats van de function trefwoord. Conceptueel gezien kun je ze beschouwen als een compacte manier om te schrijven: "neem deze parameters, evalueer deze expressie of dit codeblok en retourneer een waarde." In wezen zijn het nog steeds functies, maar ze gedragen zich op een aantal belangrijke manieren anders.

De meest eenvoudige pijlfunctie wordt rechtstreeks omgezet naar een reguliere functie-uitdrukking. Bijvoorbeeld deze klassieke functie-uitdrukking:

const multiplyByTwo = function (value) { return value * 2; };

Dit kan als een pijlfunctie worden herschreven, zoals dit:

const multiplyByTwo = (value) => { return value * 2; };

Pijlfuncties komen het best tot hun recht wanneer het lichaam één enkele expressie is. Als de body slechts één instructie is die iets retourneert, kunt u zowel de accolades als de expliciete vermelding weglaten. returnwaardoor een impliciete terugkeer mogelijk wordt:

const multiplyByTwo = value => value * 2;

Als er precies één parameter is, kunt u de omringende haakjes weglaten, maar alleen in dat specifieke geval. So x => x * 2 is geldig, maar als je nul of meerdere parameters hebt, moet je de haakjes behouden:

  • Nulparameters: () => 42
  • Eén parameter: x => x * 2 or (x) => x * 2
  • Twee of meer parameters: (x, y) => x + y

Wanneer je meer dan één zin in de hoofdtekst nodig hebt, moet je accolades en een expliciete aanduiding gebruiken. return. In die situatie gedragen pijlfuncties zich qua retourwaarde als gewone functies: nee return, geen waarde geretourneerd.

const feedCat = (status) => {
if (status === 'hungry') {
return 'Feed the cat';
} else {
return 'Do not feed the cat';
}
};

Wees voorzichtig bij het retourneren van objectliteralen vanuit pijlfuncties, omdat de accolades van het object verward kunnen worden met de functiebody. Om die dubbelzinnigheid te voorkomen, moet je de objectliteral tussen haakjes plaatsen, zodat JavaScript weet dat het een expressie is die moet worden geretourneerd:

const toObject = value => ({ result: value });

Nog één ding: pijlfuncties zijn altijd expressies, nooit declaraties. Dat betekent dat ze aan een variabele of eigenschap moeten worden toegewezen, of als argument moeten worden doorgegeven; ze kunnen niet op zichzelf staan, zoals function myFunc() {}En ze worden niet op dezelfde manier 'gehoist' als functiedeclaraties, dus je kunt ze niet aanroepen voordat ze gedefinieerd zijn.

Wat er precies is this in JavaScript?

Het trefwoord this Dit is een dynamische binding die JavaScript voor je aanmaakt wanneer het een functie of een klassemethode uitvoert. Je kunt het zien als een onzichtbare parameter waarvan de waarde afhangt van hoe en waar de functie wordt aangeroepen. Dit maakt het krachtig en flexibel, maar ook een grote bron van verwarring.

In een niet-strikte functie, this resulteert altijd in een object; in strikte modus kan het letterlijk elke waarde zijn, inclusief undefined. JavaScript bepaalt die waarde op basis van de uitvoeringscontext: reguliere functie, methodeaanroep, constructoraanroep, klasse, globale scope of pijlfunctie.

Op het hoogste niveau van een klassiek script (niet een module), this verwijst naar globalThis, wat meestal de browser is window voorwerp. De volgende vergelijking zal in een browser dus kloppen:

console.log(this === window); // true

Bij functies die geen pijlen zijn, this wordt volledig bepaald door de locatie van het gesprek. Als je belt obj.method(), dan binnen method de waarde van this is objAls je diezelfde functie neemt en deze zelfstandig aanroept als fn() in strikte modus, this wordt undefined; in de niet-strikte modus vervangt JavaScript this with globalThis.

Het belangrijkste is niet waar de functie is gedefinieerd, maar hoe deze wordt aangeroepen. Een methode kan deel uitmaken van de prototypeketen of aan een ander object worden toegewezen en toch zichtbaar blijven. this afhankelijk van welk object er daadwerkelijk wordt gebruikt op het moment van de aanroep. Het doorgeven van een methode verandert vaak de werking ervan. this tenzij je het expliciet corrigeert.

Er zijn ook hulpmiddelen om te controleren this uitdrukkelijk: call, apply, binden Reflect.apply. Hiermee kunt u de gewenste stof "injecteren". this waarde: fn.call(obj, arg1, arg2) zal uitvoeren fn with this ingesteld op objDezelfde substitutieregels gelden in de niet-strikte modus: als je doorgeeft null or undefined as this, ze worden vervangen door globalThis; primitieve gegevenstypen worden in hun omhullende objecten geplaatst.

Callbacks voegen een extra laag van indirectheid toe, omdat this wordt beheerd door degene die uw callback aanroept. Array-iteratiemethoden, de Promise De constructor en vergelijkbare API's roepen doorgaans callbacks aan met this ingesteld op undefined (of het globale object in de slordige modus). Sommige API's, zoals Array.prototype.forEach or Set.prototype.forEach, een aparte accepteren thisArg parameter die je kunt gebruiken om de callback in te stellen this.

Andere API's roepen opzettelijk callbacks aan met aangepaste this waarden. Bijvoorbeeld, de reviver argument voor JSON.parse en de replacer besteld, JSON.stringify ontvangen this Gebonden aan het object dat eigenaar is van de eigenschap die momenteel wordt verwerkt. Gebeurtenisafhandelaars in de DOM zijn gebonden aan het element waaraan ze zijn gekoppeld wanneer ze op de "klassieke" manier worden geschreven.

Het kernidee: pijlfuncties creëren hun eigen functies niet. this

Het kenmerkende van pijlfuncties is dat ze nooit een nieuwe functie creëren. this verbindend. In plaats daarvan omsluiten ze (of "veroveren") de this vanuit de omringende lexicale omgeving op het moment dat ze worden gecreëerd. Wanneer de pijl later wordt uitgevoerd, hergebruikt deze eenvoudigweg die vastgelegde waarde, ongeacht hoe je deze aanroept.

In de praktijk gedraagt ​​een pijlfunctie zich alsof deze permanent automatisch aan de pijlfunctie is gekoppeld. this van zijn uiterlijke reikwijdte. Daarom zijn methoden zoals call, applyen bind kan niet veranderen this voor een pijlfunctie: de thisArg Het argument wordt simpelweg genegeerd. Je kunt er nog steeds reguliere parameters aan doorgeven, maar de this De waarde is vergrendeld.

Bekijk dit codefragment eens in de globale scope van een scriptbestand:

const arrow = () => console.log(this);
arrow();

Omdat de pijl in de globale code is gedefinieerd, is deze this is de wereld this (typisch window (in een browserscript), en dat verandert nooit. het roepen arrow Als gewone functie zal het toewijzen ervan aan een eigenschap of het doorgeven ervan altijd hetzelfde globale object loggen wanneer het in deze context wordt aangeroepen.

Het echt interessante gedrag treedt op wanneer je pijlfuncties nestelt binnen gewone functies of methoden. Omdat de pijl de buitenste functie vastlegt thisHet wordt een krachtig hulpmiddel voor callbacks die moeten verwijzen naar het object waarin ze zich bevinden, zonder de gebruikelijke .bind(this) ceremonie.

const counter = {
id: 42,
start() {
setTimeout(() => {
console.log(this.id); // uses counter.id
}, 1000);
},
};

If start gebruikten een traditionele anonieme functie binnen setTimeoutJe zou de koppeling handmatig moeten maken. this of sla het op in een variabele. Met pijlen erft de callback op natuurlijke wijze de this vanaf startDit is counter, dus this.id prints 42 zoals bedoeld.

Deze lexicale binding verklaart ook de klassieke vraag "waarom doet dat?" this De vraag "wijzigen" bij het gebruik van pijlen in objectliteralen. Kijk eens naar deze twee objecten:

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

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

het roepen obj1.speak() prints obj1omdat speak is een gebruikelijke methode en this wordt ingesteld op basis van de locatie van het gesprek. Daarentegen obj2.speak() logs de buitenste this (vaak window in browsers), omdat de pijl het object niet als zijn thisHet object zelf creëert geen nieuw object. this bereik; alleen de functiebody doet dat, en pijlfuncties slaan die stap over.

Laten we nu een objectmethode bekijken die een innerlijke pijl creëert en deze direct aanroept:

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

obj3.speak();

In deze situatie erft de inner arrow-functie this vanaf speakDit is obj3 wanneer genoemd als obj3.speak(). Hoewel de pijl een geneste, direct aangeroepen functie is, wijst deze nog steeds naar... obj3, niet het globale object. Dat is de essentie van lexicale thisHet volgt de omringende scope, niet de aanroeplocatie van de pijl zelf.

this over functies, objecten en constructors heen

Om de pijlfuncties echt onder de knie te krijgen en thisHet helpt om te zien hoe this Werkt in alle belangrijke contexten: reguliere functies, methoden, constructors, klassen en de globale scope. Als die regels eenmaal duidelijk zijn, is het veel gemakkelijker om het gedrag van de pijl te begrijpen.

In een gewone functie (niet-pijlfunctie), this Dat hangt volledig af van hoe de functie wordt aangeroepen. Als je belt fn() in strikte modus, this is undefined; in een slordige modus zorgt vervanging ervoor dat this worden globalThis. Als je belt obj.fn()dan this is obj. Beweging fn naar een ander object of naar een variabele en de waarde van this zal dienovereenkomstig handelen.

In een methode gedefinieerd op een objectliteral, this Het object waarop de methode wordt aangeroepen, is niet per se het object waarop de methode oorspronkelijk is gedefinieerd. If obj.__proto__ bevat een methode en jij roept die aan. obj.method(), dan binnen method, this is obj, niet het prototype.

Constructors zijn een ander speciaal geval: wanneer je een functie aanroept met new, this is gekoppeld aan het zojuist aangemaakte objectexemplaar. Bijvoorbeeld, in function User(name) { this.name = name; }, bellen new User('Alex') sets this naar het nieuwe User object. Als de constructor expliciet een niet-primitief object retourneert, vervangt dat geretourneerde object het object. this als de uiteindelijke waarde van de new expressie.

De klassensyntaxis bouwt voort op deze regels met twee hoofdcontexten: instantie en statisch. Binnen een constructor of een instantiemethode, this wijst naar het klasse-exemplaar waarmee u werkt. Binnen statische methoden of statische initialisatieblokken, this verwijst naar de klasse zelf (of de afgeleide klasse wanneer deze via overerving wordt aangeroepen). Instantievelden worden geëvalueerd met this gekoppeld aan de nieuwe instantie; statische velden zie this als de klasseconstructor.

De constructors van afgeleide klassen gedragen zich iets anders: totdat je ze aanroept. super()er is geen bruikbare this. Het aanroepen super() initialiseert this door de taak te delegeren aan de basisconstructor; terugkeren voordat dat gebeurt in een afgeleide constructor is alleen toegestaan ​​als je expliciet een ander object retourneert.

In de mondiale context, this Dat hangt af van hoe de JavaScript-omgeving je code verpakt en uitvoert. In een klassiek browserscript is het hoogste niveau this is het globale object; in een ES-module is dit het topniveau. this is altijd undefinedNode.js CommonJS-modules worden intern ingekapseld en worden meestal uitgevoerd met this ingesteld op module.exportsInline-gebeurtenishandler-attributen in HTML worden uitgevoerd met this ingesteld op het element waaraan ze zijn gekoppeld.

Een subtiel maar belangrijk detail: objectliteralen zelf introduceren geen nieuwe this reikwijdte. schrijf- const obj = { value: this }; Binnen een script zal dit ervoor zorgen dat obj.value gelijk aan de buitenkant this, niet het object. Alleen functie-inhoud (en klasse-inhoud) creëert een aparte this binding; pijlen slaan deze stap opzettelijk over en erven de eigenschap over.

Waarom pijlfuncties geweldig zijn voor callbacks (en wanneer niet)

Omdat pijlfuncties sluiten over thisZe zijn uitermate geschikt voor veel callback-scenario's waarbij je wilt dat de callback blijft verwijzen naar het omringende object of de context. Dit is met name handig bij timers, promises en arraymethoden zoals map, filteren reduce.

Stel je een methode voor die een bepaalde eigenschap herhaaldelijk moet bijwerken met behulp van setInterval. Door gebruik te maken van een traditionele functie, this Binnen de callback zou standaard het globale object worden gebruikt (of zou dat zijn undefined in strikte modus), dus this.count zou niet naar jouw instantie verwijzen. Met een pijlfunctie gebruikt de callback vanzelfsprekend de this van de externe methode.

function Counter() {
this.count = 0;

setInterval(() => {
this.count++;
}, 1000);
}

Dankzij de pijl, this binnen de interval-callback wordt verwezen naar de Counter bijvoorbeeld, niet window. Als die callback een gewone functie was, zou je het volgende nodig hebben: .bind(this) of een tussenliggende variabele zoals const self = this; om de referentie te behouden.

Pijlfuncties vereenvoudigen ook code die gebruikmaakt van arraymethoden, waarbij je je vaak geen zorgen hoeft te maken over this at all. Wanneer je een traditionele functie als callback doorgeeft, is de impliciete this gewoonlijk undefinedEn dat zou je zomaar kunnen vergeten. De pijlen maken visueel duidelijk dat de functie slechts een pure afbeelding is van invoer naar uitvoer.

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

Er zijn echter belangrijke gevallen waarin pijlfuncties de verkeerde keuze zijn, met name wanneer je een dynamische functie nodig hebt. this. Twee klassieke anti-patronen zijn het gebruik van pijlfuncties als objectmethoden en als DOM-gebeurtenishandlers die afhankelijk zijn van this het element zijnde.

Stel je een object voor dat de levens van een kat bijhoudt:

const cat = {
lives: 9,
jump: () => {
this.lives--; // bug: this is not cat
},
};

cat.jump();

Sinds jump is een pijl, this verwijst niet naar cat maar wat dan ook this was de plek waar de objectliteral werd aangemaakt (vaak het globale object). de beoogde this.lives-- Ofwel wordt er een uitzondering gegenereerd (in strikte modus), ofwel wordt er stilletjes iets ongerelateerds gewijzigd. Het gebruik van een reguliere methodesyntaxis is hier de juiste aanpak.

DOM-gebeurtenislisteners zijn vergelijkbaar: het standaardpatroon this.classList.toggle('on') binnen een gebeurteniscallback is afhankelijk van this het element dat de gebeurtenis in gang zette. Met een pijlfunctie, this Het verwijst niet langer naar het element, waardoor de code niet meer werkt.

const button = document.getElementById('press');

button.addEventListener('click', () => {
this.classList.toggle('on'); // this is not button
});

In deze situatie moet de handler een normale functie zijn, zodat this wordt door de browser aan het knopelement gekoppeld. Pijlfuncties werken simpelweg niet als directe vervanging als je logica dat verwacht. this om het dynamische evenementdoelwit te zijn.

Een ander subtiel nadeel is dat pijlfuncties syntactisch anoniem zijn. Ze hebben meestal geen eigen naam (behalve de naam van de variabele waaraan ze zijn toegewezen), waardoor stacktraces iets minder beschrijvend kunnen zijn en recursie wat lastiger. In de meeste praktijkcode is dat een acceptabel compromis, maar het is goed om te onthouden.

Bijzondere gevallen: getters, setters, gebonden methoden en ongebruikelijke situaties.

Getters en setters volgen dezelfde "aanroeplocatie"-regel: this Het object waarop de eigenschap wordt benaderd, is niet het object waarop deze oorspronkelijk is gedefinieerd. Als een getter is overgeërfd van een prototype en je roept deze aan op een afgeleid object, this De getter verwijst naar het afgeleide object.

Gebonden methoden gemaakt met Function.prototype.bind Ze geven je gedrag dat enigszins lijkt op pijlfuncties, maar dan op het niveau van normale functies. Wanneer je belt f.bind(obj), je maakt een nieuwe functie waarvan this is permanent bevestigd aan obj, ongeacht hoe het wordt aangeroepen. Dit kan handig zijn in klassen wanneer je iets moet behouden. this zelfs als een methode is losgekoppeld.

class Example {
constructor() {
this.handleClick = this.handleClick.bind(this);
}

handleClick() {
console.log(this); // always the instance
}
}

Het nadeel van zowel gebonden methoden als pijlfuncties die als instantievelden worden gebruikt, is dat elke instantie een eigen kopie van de functie krijgt, wat het geheugenverbruik kan verhogen. Deze afweging is meestal acceptabel wanneer je slechts een klein aantal methoden bindt die vaak worden losgekoppeld, maar het is iets om rekening mee te houden bij prestatiekritische code.

Er zijn ook nog enkele uitzonderingen op de regel, waarbij this gedraagt ​​zich anders, bijvoorbeeld binnen een verouderde with verklaring. Binnen een with (obj) { ... } blok, waarbij een functie wordt aangeroepen die een eigenschap is van obj gedraagt ​​zich in feite alsof je het zelf had geschreven. obj.method(), dus this is gebonden aan objModerne code moet dit vermijden. withmaar inzicht in deze uitzondering verduidelijkt dat this Het hangt nog steeds fundamenteel af van hoe een functieaanroep is opgebouwd.

Inline-gebeurtenisafhandelaars in HTML hebben ook een speciale regel: de omringende inline-afhandelaarcode ziet... this als het element, maar interne functies die binnen die handler zijn gedefinieerd, vallen terug op de reguliere methode. this regels. Een innerlijke, traditionele functie, die aan niets gebonden is, zal doorgaans het volgende zien: this as globalThis (of undefined (in strikte modus), niet het element.

Onthoud tot slot dat pijlfuncties geen prototype eigenschap en kunnen niet als constructors worden gebruikt met new. Proberen new MyArrow() Dit zal een TypeError opleveren. Als je een functie nodig hebt die als constructor kan fungeren, moet je een gewone functie of een klasse gebruiken.

Door met deze details rekening te houden, wordt het veel gemakkelijker om te kiezen tussen pijltjesfuncties en traditionele functies. Gebruik pijlen waar je lexicale informatie wilt plaatsen. this en een beknopte syntaxis, en val terug op reguliere functies wanneer je de dynamische, door de aanroeplocatie gestuurde functionaliteit nodig hebt. this gedrag of constructorsemantiek.

Zodra je het eenmaal doorhebt hoe this In elke situatie zijn de pijlfuncties gebonden aan specifieke omstandigheden, waardoor ze een krachtige bondgenoot worden in plaats van een verrassende bron van fouten. Ze stroomlijnen veelvoorkomende patronen zoals callbacks en eenvoudige transformaties, terwijl reguliere functies rollen blijven vervullen die afhankelijk zijn van hun eigen functionaliteit. this bindingen, zoals methoden, constructors en dynamische gebeurtenisafhandelaars.

Gerelateerde berichten: