Welcome to Our Website

JavaScript Fabriksfunktioner vs Konstruktörsfunktioner vs klasser

före ES6 var det mycket förvirring om skillnaderna mellan en fabriksfunktion och en konstruktörsfunktion i JavaScript. Eftersom ES6 har ”klass” nyckelordet, många människor verkar tro att löst många problem med konstruktörsfunktioner. Låt oss undersöka de stora skillnaderna du fortfarande behöver vara medveten om.,

låt oss först titta på exempel på var och en:

var och en av dessa strategier lagrar metoder på en delad prototyp och stöder eventuellt privata data via konstruktörsfunktionsstängningar. Med andra ord, de har mestadels samma funktioner, och kan oftast användas omväxlande.

i JavaScript kan alla funktioner returnera ett nytt objekt. När det inte är en konstruktörsfunktion eller klass, kallas det en fabriksfunktion.,

ES6-klasser desugar till konstruktörsfunktioner, så allt som följer om konstruktörsfunktioner gäller även för ES6-klasser:

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

konstruktörer tvingar anropare att använda nyckelordetnew. Det är allt, men det har några relevanta biverkningar.

Så vad gör new nyckelord?,

Obs! vi använderinstance för att hänvisa till den nyskapade instansen ochConstructor för att hänvisa till konstruktorfunktionen eller klassen som skapade instansen.

  1. instansierar ett nytt instansobjekt och binder this till det inom konstruktören.
  2. binderinstance.__proto__ tillConstructor.prototype.
  3. som en bieffekt av 2, binderinstance.__proto__.constructortillConstructor.,
  4. returnerar implicitthis, som refererar tillinstance.

fördelar med konstruktörer& `klass`

  • de flesta böcker lär dig att använda Klass eller konstruktörer.
  • this avser det nya objektet.
  • vissa människor gillar hurmyFoo = new Foo() läser.
  • Det kan finnas en fördel med mikrooptimeringsprestanda, men du bör inte oroa dig för det om du inte har profilerat din kod och bevisat att det är ett problem för dig.,

nackdelar med konstruktörer& `klass`

innan ES6, glömmernew var ett mycket vanligt fel. För att motverka det använde många människor koilerplate för att genomdriva det:

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

i ES6+ (ES2015) om du försöker ringa en klasskonstruktör utan new kommer det alltid att kasta ett fel. Det går inte att undvika att tvinga new krav på uppringare utan att förpacka din klass i en fabriksfunktion.,

detaljer om instantiation läcka in i anropande API (via ” nya ” krav).

alla uppringare är tätt kopplade till konstruktörens implementering. Om du någonsin behöver fabrikens extra flexibilitet är refaktorn en brytförändring. Klass att fabriken refactors är tillräckligt vanligt för att de verkar i det nyskapande Refactoring bok, ”Refactoring: Förbättra Utformningen av Befintliga Koden” av Martin Fowler, Kent Beck, John Brant, William Opdyke, och Inte Roberts.,

konstruktörer bryter mot principen Öppen/Stängd

på grund av kravetnew bryter konstruktörsfunktionerna mot principen Öppen/Stängd: ett API ska vara öppet för förlängning, men stängt för modifiering.

Jag hävdar att klassen till fabriksrefaktor är tillräckligt vanlig för att den ska betraktas som en standardförlängning för alla konstruktörer: uppgradering från en klass till en fabrik ska inte bryta saker, men i JavaScript gör den det.,

om du börjar exportera en konstruktör eller klass och användare börjar använda konstruktören, sedan på vägen inser du att du behöver flexibiliteten hos en fabrik, (till exempel för att byta implementering för att använda objektpooler, eller att instansiera över exekveringsförhållanden, eller att ha mer arvsflexibilitet med alternativa prototyper), kan du inte enkelt göra det utan att tvinga en refactor på uppringare.,

tyvärr, i JavaScript, är byte från en konstruktör eller klass till en fabrik en brytningsändring:

i exemplet ovan börjar vi med en klass, men vi vill lägga till möjligheten att erbjuda olika typer av bilbuntar. För att göra det använder fabriken alternativa prototyper för olika bilbuntar. Jag har använt denna teknik för att lagra olika implementeringar av en mediaspelare gränssnitt, plocka rätt prototyp baserat på vilken typ av media spelaren som behövs för att kontrollera.,

använda konstruktörer möjliggör vilseledande `instanceof`

en av de bryta förändringar i konstruktören till fabriken refactor är instanceof. Ibland frestas människor att användainstanceof som en typkontrollvakt i sin kod. Det kan vara mycket problematiskt. Jag rekommenderar att du undviker instanceof.

`instanceof` ligger.,

instanceof skriver inte in hur du förväntar dig att liknande kontroller ska göras på starkt skrivna språk. Istället gör den en identitetskontroll som jämför objektets__proto__ – objekt med egenskapenConstructor.prototype.

det kommer inte att fungera över olika minne realms som Iframes, till exempel (en vanlig källa till buggar i 3: e parts JavaScript bäddar). Det fungerar inte heller om dittConstructor.prototype ersätts.,

det kommer också att misslyckas om du börjar med en klass eller konstruktör (som returnerar this, länkad till Constructor.prototype) och sedan byter till att exportera ett godtyckligt objekt (INTE länkat till Constructor.prototype), vilket är vad som händer när du byter från en konstruktör till en fabrik.

kort sagt,instanceof är ett annat sätt att byta från en konstruktör till en fabrik är en brytningsändring.

fördelarna med att använda Klass

  • bekväm, fristående syntax.,
  • ett enda, kanoniskt sätt att emulera klasser i JavaScript. Före ES6 fanns det flera konkurrerande implementeringar i populära bibliotek.
  • mer bekant för personer från en klassbaserad språkbakgrund.

nackdelar med att använda Klass

alla konstruktörs nackdelar, plus:

  • frestelse för användare att skapa problematiska klasshierarkier med hjälp avextends nyckelordet.,

Klasshierarkier leder till en massa välkända problem i objektorienterad design, inklusive det bräckliga basklassproblemet, Gorilla bananproblemet, dupliceringen av nödvändighetsproblemet och så vidare. Tyvärr, klass ger sträcker sig som bollar råd att kasta och stolar råd att sitta. För mer, läs ”De Två Pelarna i JavaScript: Prototypal OO” och ”Inside the Dev Team Death Spiral”.,

det är värt att notera att både konstruktörer och fabriker också kan användas för att skapa problematiska arvshierarkier, men med sökordet ”utökar” skapar klassen en överkomlighet som leder dig ner på fel väg. Med andra ord, det uppmuntrar dig att tänka i termer av oflexibel (och ofta fel) är-en relation, snarare än den mer flexibla sammansättning har-A eller kan-göra relationer.

en överkomlighet är en funktion som ger möjlighet att utföra en viss åtgärd., Till exempel, en knopp ger vridning, en spak ger dra, en knapp ger trycka, etc…

fördelarna med att använda fabriker

fabriker är mycket mer flexibla än antingen konstruktor funktioner eller klasser, och de leder inte människor ner på fel väg genom att fresta dem med ”utökar” nyckelord och djup arv hierarkier. Det finns många säkrare kod återanvändning mekanismer du bör gynna över klass arv, inklusive funktioner och moduler.,

returnera alla godtyckliga objekt och använda någon godtycklig prototyp

till exempel kan du enkelt skapa olika typer av objekt som implementerar samma API, t.ex. en mediaspelare som kan instansiera spelare för flera typer av videoinnehåll som använder olika API: er under huven, eller ett händelsebibliotek som kan avge DOM-händelser eller webbuttagshändelser.

fabriker kan också instansiera objekt över utförande sammanhang, dra nytta av objektpooler, och möjliggöra mer flexibla prototypa arv modeller.,

inga refactoring bekymmer

du skulle aldrig ha ett behov av att konvertera från en fabrik till en konstruktör, så refactoring kommer aldrig att vara ett problem.

Nej `nytt`

ingen tvetydighet om att användanew. (Det kommer att göra this beter sig dåligt, se nästa punkt).

Standard ’detta’ beteende

this fungerar som det normalt skulle, så att du kan använda den för att komma åt det överordnade objektet. Till exempel hänvisar player.create(), this till spelare, precis som vilken annan metod som helst., call() ochapply() tilldela äventhis som förväntat.

vissa människor gillar sättet `myFoo = createFoo()` läser

  • skapar inte en länk från instansen tillFactory.prototype — men det här är faktiskt en bra sak eftersom du inte får en bedrägliginstanceof. Istället kommerinstanceof alltid att misslyckas. Se förmåner.
  • this hänvisar inte till det nya objektet i fabriken. Se förmåner.,
  • Det kan fungera långsammare än en konstruktörsfunktion i mikrooptimeringsriktmärken. Den långsamma vägen är fortfarande mycket snabb-miljontals ops / sek på en gammal dator. Detta är mer sannolikt att vara ett problem i bibliotek eller ramkod än i applikationskod. Alltid riktmärke från användarperspektivet innan du använder mikrooptimeringar.

slutsats

enligt min mening kanclass ha en bekväm syntax, men det kan inte kompensera för det faktum att det lockar oönskade användare att krascha på klipporna av klass arv., Det är också riskabelt eftersom du i framtiden kanske vill uppgradera till en fabrik, men alla dina uppringare kommer att vara tätt kopplade till konstruktörsfunktionen på grund av nyckelordet new och det faktum att flyttning från klasser till fabriker är en Brytande förändring.

Du kanske tror att du bara kan refactor samtalssajterna, men på stora lag, eller om klassen du arbetar med är en del av ett offentligt API, kan du bryta kod som inte finns i din kontroll. Med andra ord kan du inte alltid anta att refactoring callers är till och med ett alternativ.,

det coola med fabriker är att de inte bara är mer kraftfulla och mer flexibla, de är också det enklaste sättet att uppmuntra hela lag och hela API-användarbaser att använda mönster som är enkla, flexibla och säkra.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *