Før ES6, det var mye forvirring om forskjellene mellom en fabrikk funksjon og en konstruktør funksjon i JavaScript. Siden ES6 har `klasse` søkeord, mange mennesker synes å mene at løst mange problemer med constructor funksjoner. Det gjorde det ikke. La oss utforske de store forskjellene du fortsatt trenger å være klar over.,
Først, la oss se på eksempler av hvert:
Hver av disse strategiene butikker metoder på en felles prototype, og eventuelt støtter private data via constructor funksjon nedleggelser. Med andre ord, de har stort sett de samme funksjonene, og kan stort sett brukes om hverandre.
I JavaScript, noen funksjon kan vende tilbake til et nytt objekt. Når det ikke er en konstruktør funksjonen eller i en klasse, er det som kalles en fabrikk funksjon.,
ES6 klasser desugar å constructor funksjoner, så alt som følger om constructor funksjoner gjelder også ES6 klasser:
class Foo {}console.log(typeof Foo); // function
Konstruktører kraft innringere til å bruke new
søkeord. Fabrikker ikke. Det er det, men som har noen aktuelle bivirkninger.
Så hva gjør new
søkeord gjøre?,
Merk: Vi vil bruke
instance
for å referere til den nyopprettede eksempel, ogConstructor
for å se constructor funksjon eller klasse som skapte eksempel.
- Instantiates en ny forekomst objekt og binder
this
til den i løpet av konstruktøren. - Binder
instance.__proto__
tilConstructor.prototype
. - Som en side-effekt av 2, binder
instance.__proto__.constructor
tilConstructor
., - Implisitt returnerer
this
, som viser tilinstance
.
Fordeler av Konstruktører & `class`
- de Fleste bøker som lærer deg å bruke klasse eller konstruktører.
-
this
refererer til det nye objektet. - Noen mennesker liker måten
myFoo = new Foo()
lyder. - Det kan være en micro-optimalisering av ytelse fordeler, men du bør ikke bekymre deg for at med mindre du har profilert koden din og bevist at det er et problem for deg.,
Ulemper av Konstruktører & `class`
Før ES6, glemmer new
var en veldig vanlig feil. For å motvirke det, mange mennesker brukte standardtekst for å håndheve det:
function Foo() {
if (!(this instanceof Foo)) { return new Foo(); }
}
I ES6+ (ES2015) hvis du prøver å ringe en klasse konstruktør uten new
, det vil alltid kaste en feil. Det er ikke mulig å unngå å tvinge new
krav på innringere uten innpakning din klasse i en fabrikk funksjon.,
Detaljer om oppretting få lekket inn i API-kall (via » ny » – krav).
Alle innringere er tett koblet til constructor gjennomføring. Hvis du noen gang trenger den ekstra fleksibiliteten i fabrikken, refactor er en bryte endre. Klasse til fabrikken refactors er vanlige nok til at de vises i den første Refactoring bok, «Refactoring: Bedre Utforming av Eksisterende Koden» av Martin Fowler, Kent Beck, John Brant, William Opdyke, og Ikke Roberts.,
Konstruktører bryte Åpen / Lukket Prinsippet
på Grunn av den new
kravet, konstruktør funksjoner bryter åpen/lukket prinsipp: en API bør være åpne for utvidelse, men stengt for endring.
jeg argumentere for at klassen til fabrikken refactor er vanlige nok til at det bør betraktes som en standard utvidelse for alle konstruktører: Oppgradering fra en klasse til en fabrikk skal ikke bryte ting, men i JavaScript, det gjør det.,
Hvis du begynner å eksportere en konstruktør eller klasse og brukere begynner å bruke konstruktøren, deretter ned den veien du innser at du trenger fleksibiliteten av en fabrikk, (for eksempel for å bytte gjennomføringen til å bruke objektet bassenger, eller å instantiate over gjennomføring sammenhenger, eller å ha mer arv fleksibilitet ved hjelp av alternative organisasjonsmodeller), kan du ikke enkelt gjøre det uten å tvinge en refactor på innringere.,
Dessverre, i JavaScript, bytte fra en konstruktør eller klasse til en fabrikk er en bryte endring:
I eksempelet ovenfor, starter vi ut med en klasse, men vi ønsker å legge til evnen til å tilby forskjellige typer bil bunter. For å gjøre dette, fabrikken bruker alternative organisasjonsmodeller for annen bil bunter. Jeg har brukt denne teknikken for å lagre ulike versjoner av en media player-grensesnittet, plukke riktig prototype basert på den type media player er nødvendig for å kontrollere.,
ved Hjelp av Konstruktører Kan Villedende `instanceof`
En av de bryte endringer i konstruktøren til fabrikken refactor er instanceof
. Noen ganger folk er fristet til å bruke instanceof
som en type sjekk vakt i koden sin. Det kan være svært problematisk. Jeg anbefaler at du unngår instanceof
.
`instanceof løgner.,
instanceof
gjør ikke skrive sjekker den måten at du forvente lignende kontroller for å gjøre i sterkt skrevet språk. I stedet, det gjør en identitet sjekk sammenligne objektet __proto__
objektet til Constructor.prototype
eiendom.
Det vil ikke fungere på tvers av ulike minne verdener som iframes, for eksempel (en felles kilde til feil i 3. part JavaScript bygger). Det er også fungerer ikke hvis din Constructor.prototype
blir erstattet.,
Det vil også mislykkes hvis du starter ut med en klasse eller konstruktør (som returnerer this
knyttet til det Constructor.prototype
), og slå deretter å eksportere et vilkårlig objekt (ikke knyttet til Constructor.prototype
), som er hva som skjer når du endrer fra en konstruktør til en fabrikk.
kort fortalt instanceof
er en annen måte som du bytter fra en konstruktør til en fabrikk er en bryte endre.
Fordelene ved Bruk av klasse
- Praktisk, selvbetjente syntaks.,
- Et enkelt, kanonisk måte å etterligne klasser i JavaScript. Før ES6, var det flere konkurrerende implementeringer i populære biblioteker.
- Mer kjent for folk fra et klasse-basert språk bakgrunnen.
Ulemper ved Hjelp av klasse
Alle av constructor ulemper, pluss:
- Fristelsen for brukere å opprette problematisk klasse hierarkier bruke
extends
søkeord.,
Klasse hierarkier føre til en haug av kjente problemer i objekt-orientert design, inkludert den skjøre base class problem, gorilla banan problem, duplisering av nødvendighet problem, og så videre. Dessverre, klasse gir strekker seg som kuler råd til å kaste og stoler råd til å sitte. For mer, kan du lese «De To Pilarene i JavaScript: Prototypal OO» og «Innsiden Dev Team Death Spiral».,
Det er verdt å merke seg at både konstruktører og fabrikker kan også brukes til å opprette problematisk arv hierarkier, men med `utvider` søkeord, klasse skaper en affordance som fører deg ned på feil vei. Med andre ord, det oppfordrer deg til å tenke i form av fastlåste (og ofte feil) er-en-relasjoner, snarere enn den mer fleksibel kompositoriske har-eller kan-gjøre-relasjoner.
En affordance er en funksjon som gir mulighet til å utføre en bestemt handling., For eksempel, en knott gir kronglete, en spak gir trekke en knapp å trykke gir, osv…
Fordeler med å Bruke Fabrikker
Fabrikker er mye mer fleksible enn enten constructor funksjoner eller klasser, og de trenger ikke føre folk nedover feil vei ved å friste dem med `utvider` nøkkelord og dyp arv hierarkier. Det er mange sikrere kode gjenbruk mekanismer bør du favør over klasse arv, inkludert funksjoner og moduler.,
Returnere alle vilkårlig objekt og bruke noe vilkårlig prototype
For eksempel, du kan enkelt lage ulike typer objekter som implementerer samme API, for eksempel en mediespiller som kan instantiate spillere for flere typer videoinnhold som bruker ulike Api-er under panseret, eller en hendelse bibliotek som kan avgi DOM hendelser eller web socket hendelser.
Fabrikker kan også instantiate gjenstander på tvers gjennomføring sammenhenger, dra nytte av objektet bassenger, og gir mulighet for mer fleksibel prototypal arv-modeller.,
Nei refactoring bekymringer
Du vil aldri få en trenger for å konvertere fra en fabrikk til en konstruktør, så refactoring vil aldri bli et problem.
No `ny`
Ingen tvetydighet om bruk av new
. Ikke gjør det. (Den vil lage this
oppfører seg dårlig, kan du se neste punkt).
Standard `dette` atferd
this
oppfører seg som det normalt ville, så du kan bruke den til å få tilgang til det overordnede objektet. For eksempel, i player.create()
, this
refererer til-spiller, akkurat som enhver annen metode ville bruken., call()
og apply()
også tilordne this
som forventet.
Noen mennesker liker måten `myFoo = createFoo()` leser
- ikke opprette en kobling fra forekomst til
Factory.prototype
— men dette er faktisk en god ting fordi du ikke vil få en villedendeinstanceof
. I stedet,instanceof
alltid vil mislykkes. Se fordelene. -
this
ikke se det nye objektet inne i fabrikken. Se fordelene., - Det kan ta lengre enn en konstruktør funksjon i mikro-optimalisering benchmarks. Den langsomme banen er fortsatt svært raskt — millioner av ops/sek på en gammel datamaskin. Dette er mer sannsynlig å være en bekymring i biblioteket eller rammeverk kode enn i programkoden. Alltid benchmark fra brukeren-perspektiv før du bruker micro-optimaliseringer.
Konklusjon
etter min mening, class
kan ha en praktisk syntaks, men som ikke kan gjøre opp for det faktum at det lokker intetanende brukere til å krasje på steinene i klasse arv., Det er også risikabelt, fordi det i fremtiden, kan du ønsker å oppgradere til en fabrikk, men alle de som ringer vil være tett koblet til constructor funksjon på grunn av new
søkeord og det faktum at flytting fra klasser til fabrikker er en bryte endre.
Du tenker kanskje at du kan bare refactor samtalen nettsteder, men på store lagene, eller hvis den klassen du arbeider med, er en del av en felles API, kan du bryte koden som ikke er under kontroll. Med andre ord, du kan ikke alltid anta at refactoring innringere er enda et alternativ.,
Den kule ting om fabrikkene er at de er ikke bare kraftigere og mer fleksibel, de er også den enkleste måten å oppmuntre til hele lag, og hele API bruker baser for å bruke mønstre som er enkle, fleksible, safe og direktetelefon.