Forud for ES6, der var en masse forvirring om forskellene mellem en fabrik funktion og en constructor-funktionen i JavaScript. Da ES6 har` klasse ‘ søgeord, en masse mennesker synes at tro, at løst mange problemer med konstruktør funktioner. Lad os undersøge de store forskelle, du stadig skal være opmærksom på.,
lad os Først se på eksempler af hver:
Hver af disse strategier butikker metoder på en delt prototype, og eventuelt støtter private data via constructor-funktion lukninger. Med andre ord, de har for det meste de samme funktioner, og kunne for det meste bruges om hverandre.
i JavaScript kan enhver funktion returnere et nyt objekt. Når det ikke er en konstruktørfunktion eller klasse, kaldes det en fabriksfunktion.,
ES6 klasser desugar til constructor-funktioner, så alt det, der følger om constructor-funktioner også gælder for ES6 klasser:
class Foo {}console.log(typeof Foo); // function
Konstruktører kraft opkald til at bruge new
søgeord. Det er det, men det har nogle bivirkninger.
Så hvad gør new
nøgleord?,
Bemærk: Vi vil bruge
instance
for at henvise til den nyoprettede eksempel, ogConstructor
for at henvise til constructor-funktion eller klasse, der har skabt eksempel.
- instantierer et nyt instansobjekt og binder
this
til det inden for konstruktøren. - Binder
instance.__proto__
tilConstructor.prototype
. - Som en side-effekt af 2, binder
instance.__proto__.constructor
tilConstructor
., - implicit returnerer
this
, som henviser tilinstance
.
fordele ved konstruktører & `klasse`
- de fleste bøger lærer dig at bruge klasse eller konstruktører.
-
this
henviser til det nye objekt. - nogle mennesker kan lide den måde
myFoo = new Foo()
læser. - der kan være en mikrooptimeringsydelse, men du bør ikke bekymre dig om det, medmindre du har profileret din kode og bevist, at det er et problem for dig.,
Ulemper af Konstruktører & `klasse`
Forud for ES6, at glemme new
var en meget almindelig fejl. For at imødegå det, mange mennesker, bruges standardteksten til at håndhæve det:
function Foo() {
if (!(this instanceof Foo)) { return new Foo(); }
}
I ES6+ (ES2015), hvis du forsøger at kalde en klasse konstruktør uden new
, vil det altid smide en fejl. Det er ikke muligt at undgå at tvingenew
krav til opkald uden at indpakke din klasse i en fabriksfunktion.,
detaljer om instantiering bliver lækket ind i den kaldende API (via det `nye` krav).
alle opkaldere er tæt koblet til konstruktørimplementeringen. Hvis du nogensinde har brug for fabrikkens ekstra fleksibilitet, er refactor en brudændring. Klasse at fabrikken refactors er fælles nok at de vises i den skelsættende Refactoring bog “Refactoring: Improving the Design of Existing Code” af Martin Fowler, Kent Beck, John Brant, William Opdyke, og Don Roberts.,
Konstruktører bryde Åbne / Lukkede Princippet
på Grund af det new
krav, constructor-funktioner, der overtræder åbne/lukkede princip: en API bør være åbent for udvidelse, men lukket for modifikation.
jeg argumenterer for, at klassen til fabriksrefaktoren er almindelig nok til, at den skal betragtes som en standardudvidelse for alle konstruktører: opgradering fra en klasse til en fabrik bør ikke bryde ting, men i JavaScript gør det det.,
Hvis du starter ud eksport af en konstruktør eller en klasse, og brugerne begynder at bruge constructor, derefter ned på den vej, du indse, du har brug for fleksibilitet for en fabrik, (for eksempel, til at skifte gennemførelsen til at bruge objektet swimmingpools, eller til at instantiere på tværs udførelse sammenhænge, eller til at have flere arv fleksibilitet ved hjælp af alternative prototyper), ikke kan du nemt gøre det uden at tvinge en refactor på opkald.,
Desværre, i JavaScript, skifte fra en konstruktør eller klasse til en fabrik er en bryde ændring:
I eksemplet ovenfor, starter vi ud med en klasse, men vi vil tilføje mulighed for at tilbyde forskellige former for bil bundter. For at gøre det bruger fabrikken alternative prototyper til forskellige bilbundter. Jeg har brugt denne teknik til at gemme forskellige implementeringer af en medieafspillergrænseflade og vælge den rigtige prototype baseret på den type medie, som afspilleren har brug for til at kontrollere.,
brug af konstruktører muliggør den vildledende `instanceof`
en af de brydningsændringer i konstruktøren til fabriksrefaktoren er instanceof
. Nogle gange er folk fristet til at bruge instanceof
som en type check guard i deres kode. Det kan være meget problematisk. Jeg anbefaler, at du undgår instanceof
.
`instanceof` løgne.,
instanceof
ikke vil skrive, at kontrollere den måde, som du forventer tilsvarende kontrol at gøre i stærkt typet sprog. I stedet foretager den en identitetskontrol, der sammenligner objektets__proto__
objekt tilConstructor.prototype
ejendom.
det vil ikke arbejde på tværs af forskellige hukommelse riger som iframes, for eksempel (en fælles kilde til fejl i 3.parts JavaScript integrerer). Det virker heller ikke, hvis dit Constructor.prototype
bliver erstattet.,
Det vil også fejle, hvis du starter ud med en klasse eller en konstruktør (som returnerer this
, der er knyttet til Constructor.prototype
), og derefter skifte til at eksportere et vilkårligt objekt (som ikke er knyttet til Constructor.prototype
), hvilket er, hvad der sker, når du ændrer fra en konstruktør til en fabrik.
kort sagt, instanceof
er en anden måde, hvorpå skift fra en konstruktør til en fabrik er en brudændring.
fordele ved at bruge klasse
- praktisk, selvstændig syntaks.,
- en enkelt, kanonisk måde at efterligne klasser i JavaScript. Før ES6 var der flere konkurrerende implementeringer i populære biblioteker.
- mere kendt for folk fra en klassebaseret sprogbaggrund.
ulemper ved at bruge klasse
alle konstruktør ulemper, plus:
- fristelse for brugere til at oprette problematiske klassehierarkier ved hjælp af
extends
nøgleord.,
Klassehierarkier fører til en masse velkendte problemer i objektorienteret design, herunder det skrøbelige baseklasseproblem, gorilla banana-problemet, duplikering af nødvendighedsproblem og så videre. Desværre giver klassen strækker sig som bolde råd til at kaste og stole råd til at sidde. For mere, læs “de to søjler i JavaScript: Prototypal OO” og “inde i Dev Team Death Spiral”.,
det er værd at bemærke, at både konstruktører og fabrikker også kan bruges til at skabe problematiske arvehierarkier, men med nøgleordet `udvider` skaber klassen en overkommelighed, der fører dig ned ad den forkerte vej. Med andre ord, det opfordrer dig til at tænke i form af ufleksible (og ofte forkert) er-et forhold, snarere end den mere fleksible kompositoriske har-A eller kan-gøre relationer.
en overkommelighed er en funktion, der giver mulighed for at udføre en bestemt handling., For eksempel, en knop giver vride et håndtag giver trække en knap giver trykke på osv…
Fordele ved at Bruge Fabrikker
Fabrikker er meget mere fleksible end enten constructor-funktioner eller-klasser, og de behøver ikke lede mennesker ad den forkerte sti, ved at friste dem med `udvider` søgeord og dybt arv hierarkier. Der er mange sikrere kode genbrug mekanismer, du bør favorisere over klasse arv, herunder funktioner og moduler.,
Returnere enhver vilkårlig objekt og bruge alle vilkårlige prototype
For eksempel, kan du nemt oprette forskellige typer af objekter, der implementerer det samme API, fx, en medieafspiller, der kan instantiere spillere for flere typer af video-indhold, som bruger forskellige Api ‘ er under motorhjelmen, eller en begivenhed, bibliotek, som kan udsende DOM begivenheder eller web socket begivenheder.
Fabrikker kan også instantiere objekter på tværs udførelse sammenhænge, drage fordel af objekt swimmingpools, og give mulighed for mere fleksibel prototypal arv modeller.,
ingen refactoring bekymringer
du ville aldrig have behov for at konvertere fra en fabrik til en konstruktør, så refactoring vil aldrig være et problem.
ingen”ny”
ingen tvetydighed om at bruge new
. Ikke. (det vil gøre this
opfører sig dårligt, se næste punkt).
Standard `dette` adfærd
this
opfører sig, som det normalt ville, så du kan bruge det til at få adgang til det overordnede objekt. For eksempel inde player.create()
, this
refererer til spiller, ligesom enhver anden metode påkaldelse ville., call()
og apply()
også overflytte this
som forventet.
Nogle mennesker kan godt lide den måde `myFoo = createFoo()` læser
- ikke lave et link fra instans til
Factory.prototype
— men det er faktisk en god ting, fordi du ikke vil få en vildledendeinstanceof
. I stedet vilinstanceof
altid mislykkes. Se fordele. -
this
henviser ikke til det nye objekt inde i fabrikken. Se fordele., - det kan udføre langsommere end en konstruktør funktion i mikro-optimering benchmarks. Den langsomme vej er stadig meget hurtig-millioner af ops / SEK på en gammel computer. Dette er mere sandsynligt, at det er et problem i bibliotek eller rammekode end i applikationskode. Benchmark altid fra brugerperspektivet, før du bruger mikrooptimeringer.
Konklusion
efter min mening, class
kan have en praktisk syntaks, men det kan ikke gøre op for det faktum, at det lokker uforsigtige brugere til at gå ned på klipperne klasse arv., Det er også risikabelt, fordi der i fremtiden, kan du overveje at opgradere til en fabrik, men alle dine opkald vil blive tæt koblet til constructor-funktion på grund af new
søgeord og det faktum, at flytte fra klasser til fabrikker er en bryde ændre.
du tænker måske, at du bare kan refactor opkaldssiderne, men på store hold, eller hvis den klasse, du arbejder med, er en del af et offentligt API, kan du bryde kode, der ikke er i din kontrol. Med andre ord kan du ikke altid antage, at refactoring-opkald endda er en mulighed.,
Det fede ved fabrikker er, at de er ikke bare mere effektivt og mere fleksibelt, de er også den nemmeste måde at tilskynde til hele hold, og hele API-bruger baser til at bruge mønstre, der er enkle, fleksible og sikre.