Welcome to Our Website

JavaScript Factory Functions vs Constructor Functions vs Classes

voorafgaand aan ES6 was er veel verwarring over de verschillen tussen een factory function en een constructor function in JavaScript. Aangezien ES6 het `klasse` sleutelwoord heeft, lijken veel mensen te denken dat dit veel problemen met constructorfuncties heeft opgelost. Laten we de grote verschillen onderzoeken waar je je nog bewust van moet zijn.,

laten we eerst eens kijken naar voorbeelden van elk:

elk van deze strategieën slaat methoden op op een gedeeld prototype, en ondersteunt optioneel privégegevens via Constructor functie sluitingen. Met andere woorden, ze hebben meestal dezelfde functies, en kunnen meestal door elkaar worden gebruikt.

in JavaScript kan elke functie een nieuw object retourneren. Als het geen constructorfunctie of klasse is, wordt het een fabrieksfunctie genoemd.,

ES6-klassen desugar naar constructorfuncties, dus alles wat volgt over constructorfuncties is ook van toepassing op ES6-klassen:

class Foo {}console.log(typeof Foo); // function

Constructors dwingen bellers om het new sleutelwoord te gebruiken. Fabrieken niet. dat is het, maar dat heeft een aantal relevante bijwerkingen.

dus wat doet het new sleutelwoord?,

opmerking: we gebruikeninstance om te verwijzen naar de nieuw aangemaakte instantie, enConstructor om te verwijzen naar de constructorfunctie of-klasse die de instantie heeft gemaakt.

  1. Instanteert een nieuw instantieobject en bindt this aan het object binnen de constructor.
  2. bindt instance.__proto__ aan Constructor.prototype.
  3. als bijwerking van 2 bindt instance.__proto__.constructor aan Constructor.,
  4. geeft impliciet this terug, wat verwijst naar instance.

voordelen van constructeurs & `klasse`

  • De meeste boeken leren u om klasse of constructeurs te gebruiken.
  • this verwijst naar het nieuwe object.
  • sommige mensen houden van de manier waarop myFoo = new Foo() leest.
  • Er kan een micro-optimalisatie prestatie voordeel zijn, maar je moet je daar geen zorgen over maken, tenzij je je code hebt geprofileerd en bewezen hebt dat het een probleem voor je is.,

nadelen van Constructors & `class`

voor ES6 was het vergeten van new een veel voorkomende fout. Om het tegen te gaan, gebruikten veel mensen boilerplate om het af te dwingen:

function Foo() {
if (!(this instanceof Foo)) { return new Foo(); }
}

in ES6+ (ES2015) als je een class constructor probeert aan te roepen zonder new, zal het altijd een fout geven. Het is niet mogelijk om de eis van new voor bellers te vermijden zonder uw klasse in een fabrieksfunctie te wikkelen.,

Details van instantiation worden gelekt in de aanroepende API (via de` nieuwe ‘ eis).

Alle bellers zijn nauw gekoppeld aan de implementatie van de constructor. Als u ooit de extra flexibiliteit van de fabriek nodig heeft, is de refactor een breukverandering. Class to factory refactors komen vaak voor in het baanbrekende Refactoring boek “Refactoring: Improving the Design of Existing Code” van Martin Fowler, Kent Beck, John Brant, William Opdyke en Don Roberts.,

Constructors breken het Open/Gesloten Principe

vanwege de new vereiste schenden constructorfuncties het open / gesloten principe: een API moet open zijn voor uitbreiding, maar gesloten voor wijziging.

Ik beargumenteer dat de class to factory refactor algemeen genoeg is dat het beschouwd moet worden als een standaard extensie voor alle constructeurs: upgraden van een class naar een factory zou geen dingen moeten breken, maar in JavaScript wel.,

als je begint met het exporteren van een constructor of klasse en gebruikers beginnen de constructor te gebruiken, dan realiseer je je dat je de flexibiliteit van een fabriek nodig hebt (bijvoorbeeld om de implementatie om te schakelen naar objectpools, of om te instantiëren over uitvoercontexten, of om meer overerving flexibiliteit te hebben met behulp van alternatieve prototypes), je kunt dit niet gemakkelijk doen zonder een refactor op bellers te forceren.,

helaas is het overschakelen van een constructor of klasse naar een fabriek in JavaScript een breuk:

in het bovenstaande voorbeeld beginnen we met een klasse, maar we willen de mogelijkheid toevoegen om verschillende soorten auto-bundels aan te bieden. Om dit te doen, gebruikt de fabriek alternatieve prototypes voor verschillende auto bundels. Ik heb deze techniek gebruikt om verschillende implementaties van een media player-interface op te slaan, het kiezen van de juiste prototype op basis van het type media dat de speler nodig heeft om te controleren.,

het gebruik van Constructors maakt de bedrieglijke ‘instanceof’

een van de breukwijzigingen in de constructor naar de fabrieksreactor is instanceof. Soms zijn mensen geneigd om instanceof te gebruiken als een type controle guard in hun code. Dat kan erg problematisch zijn. Ik raad u aan instanceofte vermijden.

`instanceof` lies.,

instanceofcontroleert niet de manier waarop u soortgelijke controles verwacht te doen in stronged talen. In plaats daarvan wordt een identiteitscontrole uitgevoerd waarbij het object __proto__ wordt vergeleken met de eigenschap Constructor.prototype.

het zal niet werken in verschillende geheugenrijken zoals iframes, bijvoorbeeld (een veel voorkomende bron van bugs in JavaScript-insluitingen van derden). Het werkt ook niet als uw Constructor.prototype wordt vervangen.,

Het zal ook mislukken als u begint met een klasse of constructor (die this retourneert, gekoppeld aan Constructor.prototype), en dan overschakelt naar het exporteren van een willekeurig object (niet gekoppeld aan Constructor.prototype), wat gebeurt als u van een constructor naar een fabriek overstapt.

kortom, instanceof is een andere manier waarop overschakelen van een constructor naar een fabriek een breuk is.

voordelen van het gebruik van klasse

  • Handige, op zichzelf staande syntaxis.,
  • een enkele, canonieke manier om klassen in JavaScript te emuleren. Voorafgaand aan ES6 waren er verschillende concurrerende implementaties in populaire bibliotheken.
  • meer vertrouwd bij mensen met een op klasse gebaseerde taalachtergrond.

nadelen van het gebruik van klasse

alle nadelen van de constructor, plus:

  • verleiding voor gebruikers om problematische klassenhiërarchieën te creëren met behulp van het extends sleutelwoord.,

Klassenhiërarchieën leiden tot een aantal bekende problemen in objectgeoriënteerd ontwerp, waaronder het fragiele baseklasse probleem, het gorilla banana probleem, het duplicatie door noodzaak probleem, enzovoort. Helaas, klasse biedt strekt zich uit als ballen veroorloven gooien en stoelen veroorloven zitten. Lees voor meer informatie ” the Two Pillars of JavaScript: Prototypal OO “en”Inside The Dev Team Death Spiral”.,

Het is vermeldenswaard dat zowel constructeurs als fabrieken ook kunnen worden gebruikt om problematische erfelijkheidshiërarchieën te creëren, maar met het `breidt` sleutelwoord, class creëert een affordance die je op het verkeerde pad leidt. Met andere woorden, het moedigt je aan om te denken in termen van inflexibele (en vaak verkeerde) is-a relaties, in plaats van de meer flexibele samenstelling heeft-a of kan-doen relaties.

een affordance is een functie die de mogelijkheid biedt om een bepaalde actie uit te voeren., Bijvoorbeeld, een knop laat draaien, een hendel laat trekken, een knop laat drukken, etc…

voordelen van het gebruik van fabrieken

fabrieken zijn veel flexibeler dan constructorfuncties of klassen, en ze leiden mensen niet op het verkeerde pad door hen te verleiden met het `verlengt` sleutelwoord en diepe overerving hiërarchieën. Er zijn veel veiliger code reuse mechanismen die je zou moeten verkiezen boven klasse overerving, met inbegrip van functies en modules.,

retourneer elk willekeurig object en gebruik elk willekeurig prototype

U kunt bijvoorbeeld eenvoudig verschillende typen objecten maken die dezelfde API implementeren, bijvoorbeeld een mediaspeler die spelers kan instantiëren voor meerdere soorten video-inhoud die verschillende API ‘ s Onder de motorkap gebruiken, of een gebeurtenisbibliotheek die DOM-gebeurtenissen of WebSocket-gebeurtenissen kan uitzenden.

fabrieken kunnen ook objecten in uitvoercontexten instantiëren, gebruik maken van objectpools en flexibelere prototypale overerving-modellen mogelijk maken.,

geen refactoring zorgen

u hoeft nooit van een fabriek naar een constructor te converteren, dus refactoring zal nooit een probleem zijn.

geen `nieuw`

geen dubbelzinnigheid over het gebruik van new. Niet doen. (het zal this zich slecht gedragen, zie het volgende punt).

Standaard` dit ‘ gedrag

this gedraagt zich zoals het normaal zou zijn, dus u kunt het gebruiken om toegang te krijgen tot het bovenliggende object. Bijvoorbeeld, binnen player.create(), this verwijst naar de speler, net als elke andere methode aanroep zou doen., call() en apply() ook this opnieuw toewijzen zoals verwacht.

sommige mensen houden van de manier waarop` myFoo = createFoo () ‘ leest

  • maakt geen link aan van de instantie naar Factory.prototype — maar dit is eigenlijk een goede zaak omdat je geen misleidende instanceofkrijgt. In plaats daarvan zal instanceof altijd falen. Zie voordelen.
  • this verwijst niet naar het nieuwe object in de fabriek. Zie voordelen.,
  • Het kan langzamer werken dan een constructorfunctie in micro-optimalisatie benchmarks. Het langzame pad is nog steeds erg snel-miljoenen ops / sec op een oude computer. Dit is eerder een probleem in de bibliotheek of framework code dan in de applicatie code. Benchmark altijd vanuit het gebruikersperspectief voordat u micro-optimalisaties gebruikt.

conclusie

naar mijn mening kan class Een handige syntaxis hebben, maar dat kan het feit niet goedmaken dat het onoplettende gebruikers lokt om te crashen op de rotsen van klasse-overerving., Het is ook riskant omdat u in de toekomst misschien wilt upgraden naar een fabriek, maar al uw bellers zullen strak gekoppeld zijn aan de constructorfunctie vanwege het new sleutelwoord en het feit dat het verplaatsen van klassen naar fabrieken een brekende verandering is.

je denkt misschien dat je gewoon de aanroep sites kunt refactor, maar op grote teams, of als de klasse waarmee je werkt deel uitmaakt van een openbare API, je zou kunnen breken code die niet in uw controle. Met andere woorden, je kunt niet altijd aannemen dat refactoring bellers is zelfs een optie.,

Het leuke aan fabrieken is dat ze niet alleen krachtiger en flexibeler zijn, ze zijn ook de makkelijkste manier om hele teams en hele API-gebruikersbases aan te moedigen om patronen te gebruiken die eenvoudig, flexibel en veilig zijn.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *