Welcome to Our Website

JavaScript Factory Functions vs Constructor Functions vs Classes (Polski)

przed ES6 było wiele nieporozumień co do różnic między funkcją factory a funkcją konstruktora w JavaScript. Ponieważ ES6 ma słowo kluczowe ' class`, Wiele osób wydaje się myśleć, że rozwiązało to wiele problemów z funkcjami konstruktora. Zbadajmy główne różnice, których musisz być świadomy.,

najpierw spójrzmy na przykłady każdej z nich:

każda z tych strategii przechowuje metody na współdzielonym prototypie i opcjonalnie obsługuje prywatne dane poprzez zamknięcie funkcji konstruktora. Innymi słowy, mają one w większości te same funkcje i mogą być używane zamiennie.

w JavaScript każda funkcja może zwrócić nowy obiekt. Gdy nie jest to funkcja konstruktora lub klasa, nazywa się ją funkcją fabryczną.,

klasy ES6 desugar do funkcji konstruktora, więc wszystko, co następuje o funkcjach konstruktora, odnosi się również do klas ES6:

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

konstruktory zmuszają wywołujących do użycia słowa kluczowegonew. To wszystko, ale to ma istotne skutki uboczne.

do czego służy słowo kluczowenew?,

Uwaga: użyjemyinstance aby odnieść się do nowo utworzonej instancji, aConstructor aby odnieść się do funkcji konstruktora lub klasy, która utworzyła instancję.

  1. tworzy instancję nowego obiektu instancji i wiąże z nimthis w konstruktorze.
  2. wiążeinstance.__proto__ doConstructor.prototype.
  3. jako efekt uboczny 2, wiążeinstance.__proto__.constructor doConstructor.,
  4. domyślnie zwracathis, co odnosi się doinstance.

zalety konstruktorów& `class`

  • większość książek uczy używania klas lub konstruktorów.
  • this odnosi się do nowego obiektu.
  • niektórym podoba się sposóbmyFoo = new Foo() czyta.
  • może wystąpić korzyść z mikro-optymalizacji, ale nie powinieneś się tym martwić, chyba że sprofilowałeś swój kod i udowodniłeś, że jest to problem dla Ciebie.,

wady konstruktorów & `class`

przed ES6 zapominanie new było bardzo częstym błędem. Aby go przeciwdziałać, Wiele osób używało boilerplate, aby go wymusić:

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

w ES6+ (ES2015) jeśli spróbujesz wywołać konstruktor klasy bez new, zawsze spowoduje to błąd. Nie jest możliwe uniknięcie wymuszenia wymogu new na rozmówców bez zawijania klasy w funkcję fabryczną.,

szczegóły instancji zostaną wycieknięte do wywołującego API (poprzez wymóg `nowy`).

wszystkie wywołujące są ściśle powiązane z implementacją konstruktora. Jeśli kiedykolwiek potrzebujesz dodatkowej elastyczności fabryki, refaktor jest przełomową zmianą. Klasy do fabrycznych refaktorów są na tyle powszechne, że pojawiają się w przełomowej książce Refaktoringowej „Refactoring: Improving the Design of Existing Code” autorstwa Martina Fowlera, Kenta Becka, Johna Branta, Williama Opdyke i Dona Robertsa.,

konstruktory łamią zasadę Open/Closed

ze względu na wymaganianew funkcje konstruktora łamią zasadę open / closed: API powinno być otwarte dla rozszerzenia, ale zamknięte dla modyfikacji.

argumentuję, że klasa do factory refactor jest na tyle powszechna, że powinna być uważana za standardowe rozszerzenie dla wszystkich konstruktorów: aktualizacja z klasy do fabryki nie powinna niszczyć rzeczy, ale w JavaScript tak.,

Jeśli zaczniesz eksportować konstruktor lub klasę, A użytkownicy zaczną go używać, to po drodze zdasz sobie sprawę, że potrzebujesz elastyczności fabryki (na przykład, aby zmienić implementację, aby użyć pul obiektów, lub utworzyć instancję w różnych kontekstach wykonania, lub aby uzyskać większą elastyczność dziedziczenia przy użyciu alternatywnych prototypów), nie możesz tego łatwo zrobić bez wymuszania refaktor na wywołujących.,

Niestety w JavaScript przejście z konstruktora lub klasy do fabryki jest przełomową zmianą:

w powyższym przykładzie zaczynamy od klasy, ale chcemy dodać możliwość oferowania różnych rodzajów pakietów samochodowych. W tym celu fabryka wykorzystuje alternatywne prototypy dla różnych pakietów samochodów. Użyłem tej techniki do przechowywania różnych implementacji interfejsu odtwarzacza multimedialnego, wybierając prawidłowy prototyp w oparciu o rodzaj mediów, którymi odtwarzacz musiał sterować.,

używanie konstruktorów umożliwia zwodnicze `instanceof`

jedną z przełomowych zmian w konstruktorze na fabryczny refaktor jest instanceof. Czasami ludzie są kuszeni, aby użyć instanceof jako osłony kontroli typu w swoim kodzie. To może być bardzo problematyczne. Polecam unikać instanceof.

`instanceof` lies.,

instanceof kontrole do wykonania w silnie wpisanych językach. Zamiast tego sprawdza tożsamość porównując obiekt __proto__ z właściwościąConstructor.prototype.

nie będzie działać w różnych obszarach pamięci, takich jak iframes, na przykład(wspólne źródło błędów w 3rd party JavaScript osadza). Nie działa również, jeśli twój Constructor.prototype zostanie zastąpiony.,

również się nie powiedzie, jeśli zaczniesz od klasy lub konstruktora (który zwraca this, połączonego zConstructor.prototype), a następnie przełączysz się na eksport dowolnego obiektu (nie połączonego zConstructor.prototype), co dzieje się po zmianie konstruktora na fabryczny.

w skrócie,instanceof jest innym sposobem, w którym przejście z konstruktora do fabryki jest zmianą przełomową.

zalety korzystania z klasy

  • wygodna, samodzielna składnia.,
  • pojedynczy, kanoniczny sposób emulowania klas w JavaScript. Przed ES6 istniało kilka konkurencyjnych implementacji w popularnych bibliotekach.
  • bardziej znane osobom z klasowego środowiska językowego.

wady używania klasy

wszystkie wady konstruktora, plus:

  • pokusa dla użytkowników do tworzenia problematycznych hierarchii klas za pomocą słowa kluczowego extends.,

hierarchie klas prowadzą do szeregu dobrze znanych problemów w projektowaniu obiektowym, w tym problemu kruchej klasy bazowej, problemu goryla banana, problemu powielania przez konieczność i tak dalej. Niestety, Klasa daje tak jak piłki pozwalają na rzucanie, a krzesła na siedzenie. Aby dowiedzieć się więcej, przeczytaj „dwa filary JavaScript: Prototypal OO” i „Inside the Dev Team Death Spiral”.,

warto zauważyć, że zarówno konstruktory, jak i fabryki mogą być również używane do tworzenia problematycznych hierarchii dziedziczenia, ale za pomocą słowa kluczowego `extends`, class tworzy affordance, który prowadzi Cię na złą ścieżkę. Innymi słowy, zachęca do myślenia w kategoriach nieelastycznych (i często błędnych) relacji jest-a, a nie bardziej elastycznego składu ma-a lub może-zrobić relacje.

affordance to funkcja, która daje możliwość wykonania określonej czynności., Na przykład, pokrętło umożliwia skręcanie, dźwignia umożliwia ciągnięcie, przycisk umożliwia naciśnięcie, itp…

korzyści z używania fabryk

fabryki są znacznie bardziej elastyczne niż funkcje konstruktorów lub klasy, i nie prowadzą ludzi na złą drogę, kusząc ich słowem kluczowym `extends` i głębokimi hierarchiami dziedziczenia. Istnieje wiele bezpieczniejszych mechanizmów ponownego użycia kodu, które powinieneś faworyzować nad dziedziczeniem klas, w tym funkcje i moduły.,

zwróć dowolny dowolny obiekt i użyj dowolnego prototypu

na przykład możesz łatwo tworzyć różne typy obiektów, które implementują ten sam interfejs API, np. odtwarzacz multimedialny, który może tworzyć instancje dla wielu typów treści wideo, które używają różnych interfejsów API pod maską, lub bibliotekę zdarzeń, która może emitować zdarzenia DOM lub zdarzenia gniazda sieciowego.

fabryki mogą również tworzyć instancje obiektów w różnych kontekstach wykonania, korzystać z pul obiektów i pozwalać na bardziej elastyczne modele dziedziczenia prototypów.,

bez obaw o refaktoryzację

nigdy nie będziesz musiał konwertować z fabryki na konstruktor, więc refaktoryzacja nigdy nie będzie problemem.

brak` nowego '

brak niejasności co do używania new. Nie. (spowoduje to, że this zachowa się źle, patrz następny punkt).

standardowe zachowanie `this`

this zachowuje się tak, jak normalnie, więc możesz go użyć, aby uzyskać dostęp do obiektu nadrzędnego. Na przykład, wewnątrz player.create(), this odnosi się do odtwarzacza, tak jak każde inne wywołanie metody., call() Iapply() również zmienićthis zgodnie z oczekiwaniami.

niektórzy ludzie lubią sposób, w jaki `myfoo = createFoo()` odczytuje

  • nie tworzy łącza z instancji do Factory.prototype — ale jest to właściwie dobra rzecz, ponieważ nie otrzymasz zwodniczego instanceof. Zamiast tego instanceof zawsze się nie powiedzie. Zobacz korzyści.
  • this nie odnosi się do nowego obiektu wewnątrz fabryki. Zobacz korzyści.,
  • może działać wolniej niż funkcja konstruktora w testach mikro-optymalizacji. Powolna ścieżka jest nadal bardzo szybka-miliony operacji/SEK na starym komputerze. Jest to bardziej prawdopodobne w kodzie biblioteki lub frameworka niż w kodzie aplikacji. Zawsze porównuj z punktu widzenia użytkownika przed użyciem mikro-optymalizacji.

podsumowanie

moim zdaniem class może mieć wygodną składnię, ale to nie może nadrobić faktu, że zwabia nieświadomych użytkowników do awarii na skałach dziedziczenia klas., Jest to również ryzykowne, ponieważ w przyszłości możesz chcieć uaktualnić do fabryki, ale wszyscy Twoi rozmówcy będą ściśle powiązani z funkcją konstruktora ze względu na słowo kluczowe new I fakt, że przejście z klas do fabryki jest przełomową zmianą.

możesz myśleć, że możesz po prostu refaktorować strony połączeń, ale w dużych zespołach lub jeśli klasa, z którą pracujesz, jest częścią publicznego API, możesz złamać kod, który nie jest pod twoją kontrolą. Innymi słowy, nie zawsze można zakładać, że refaktoryzacja rozmówców jest nawet opcją.,

fajną rzeczą w fabrykach jest to, że są one nie tylko wydajniejsze i bardziej elastyczne, ale także najprostszym sposobem na zachęcenie całych zespołów i całych baz użytkowników API do korzystania z szablonów, które są proste, elastyczne i bezpieczne.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *