Hoe een JavaScript functie correct te omwikkelen

, Author

Met het omwikkelen van JavaScript functies kun je gemeenschappelijke logica toevoegen aan functies die je niet controleert, zoals native en externe functies. Veel JavaScript bibliotheken, zoals de TrackJS agents, moeten externe functies wrappen om hun werk te doen. Het toevoegen van wrappers stelt ons in staat om te luisteren naar telemetrie, fouten en logs in je code, zonder dat je onze API expliciet hoeft aan te roepen.

Je kunt een functie willen wrappen om instrumentatie of tijdelijke debugging-logica toe te voegen. U kunt ook het gedrag van een externe bibliotheek wijzigen zonder de broncode te hoeven wijzigen.

Basic Function Wrapping

Omdat JavaScript zo dynamisch is, kunnen we een functie wikkelen door eenvoudig de functie opnieuw te definiëren met iets nieuws. Neem bijvoorbeeld dit wrappen van myFunction:

In dit triviale voorbeeld hebben we het oorspronkelijke myFunction gewrapped en een logboekboodschap toegevoegd. Maar er is een heleboel dingen die we niet hebben behandeld:

  • Hoe geven we functie-argumenten door?
  • Hoe behouden we scope (de waarde van this)?
  • Hoe krijgen we de return-waarde?
  • Wat als er een fout optreedt?

Om met deze dingen om te gaan, moeten we een beetje slimmer worden in onze verpakking.

Merk op dat we in dit voorbeeld niet alleen de functie aanroepen, maar call-ingrijpen met de waarde voor this en de argumenten a, b, en c. De waarde van this zal worden doorgegeven vanaf de plaats waar u uw gewrapte functie vastmaakt, Window in dit voorbeeld.

We hebben ook de hele functie omgeven in een try/catch blok, zodat we aangepaste logica kunnen oproepen in het geval van een fout, de functie opnieuw kunnen gooien, of een standaard waarde kunnen teruggeven.

Geavanceerde Functie Wrapping

Het basis voorbeeld zal 90% van de tijd werken, maar als je gedeelde bibliotheken bouwt, zoals de TrackJS agents, is dat niet goed genoeg! Om onze functies als een pro te wikkelen, zijn er enkele randgevallen waar we mee om moeten gaan:

  • Wat met niet gedeclareerde of onbekende argumenten?
  • Hoe komen we overeen met de functie handtekening?
  • Hoe spiegelen we functie eigenschappen?

Er zijn 3 subtiele maar belangrijke veranderingen. Ten eerste (#1), we hebben de functie een naam gegeven. Het lijkt overbodig, maar gebruikerscode kan de waarde van function.name controleren, dus is het belangrijk om de naam te behouden bij het wrappen.

De tweede verandering (#2) is in hoe we de gewrapte functie noemen, door apply te gebruiken in plaats van call. Dit stelt ons in staat om een arguments object door te geven, wat een array-achtig object is van alle argumenten die in runtime aan de functie worden doorgegeven. Hierdoor kunnen we functies ondersteunen die een ongedefinieerd of variabel aantal argumenten kunnen hebben.

Met apply hebben we de argumenten a, b, en c niet nodig die in de functie-eigenschap zijn gedefinieerd. Maar door dezelfde argumenten te blijven opgeven als in de oorspronkelijke functie, behouden we de ariteit van de functie. Dat wil zeggen, Function.length geeft het aantal argumenten terug dat in de signatuur is gedefinieerd, en dit zal de originele functie weerspiegelen.

De laatste wijziging (#3) kopieert alle door de gebruiker gespecificeerde eigenschappen van de originele functie naar onze wrapping.

Limitaties

Deze wrapping is grondig, maar er zijn altijd beperkingen in JavaScript. In het bijzonder is het moeilijk om een functie met een niet-standaard prototype, zoals een object constructor, correct te wrappen. Dit is een use case die beter door overerving kan worden opgelost.

In het algemeen is het veranderen van het prototype van een functie mogelijk, maar het is geen goed idee. Er zijn ernstige prestatie-implicaties en onbedoelde neveneffecten bij het manipuleren van prototypes.

Respect the Environment

Function wrapping geeft je veel macht om de JavaScript-omgeving te instrumenteren en te manipuleren. Je hebt een verantwoordelijkheid om die macht verstandig te gebruiken. Als je functie-wrappers bouwt, respecteer dan de gebruiker en de omgeving waarin je opereert. Er kunnen andere wrappers zijn, andere luisteraars voor gebeurtenissen, en verwachtingen over functie-API’s. Doe het rustig aan en breek geen externe code af.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.