Funkcja konstruktora a funkcje fabryczne
Czy ktoś może wyjaśnić różnicę między funkcją konstruktora a funkcją fabryczną w Javascript.
Kiedy używać jednego zamiast drugiego?
7 answers
Podstawowa różnica polega na tym, że funkcja konstruktora jest używana ze słowem kluczowym new
(co powoduje, że JavaScript automatycznie tworzy nowy obiekt, ustawia this
wewnątrz funkcji do tego obiektu i zwraca obiekt):
var objFromConstructor = new ConstructorFunction();
Funkcja fabryczna jest nazywana jak funkcja "regularna":
var objFromFactory = factoryFunction();
Ale aby była uważana za "fabryczną", musiałaby zwrócić nową instancję jakiegoś obiektu: nie nazwałbyś jej funkcją" fabryczną", gdyby po prostu zwróciła wartość logiczną czy coś takiego. Nie dzieje się to automatycznie, jak w przypadku new
, ale pozwala to na większą elastyczność w niektórych przypadkach.
W bardzo prostym przykładzie funkcje wymienione powyżej mogą wyglądać mniej więcej tak:
function ConstructorFunction() {
this.someProp1 = "1";
this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };
function factoryFunction() {
var obj = {
someProp1 : "1",
someProp2 : "2",
someMethod: function() { /* whatever */ }
};
// other code to manipulate obj in some way here
return obj;
}
Oczywiście można znacznie bardziej skomplikować funkcje fabryczne niż ten prosty przykład.
Jedną z zalet funkcji fabrycznych jest to, że zwracany obiekt może być kilku różnych typów w zależności od jakiegoś parametru.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-15 01:30:41
Korzyści z używania konstruktorów
Większość książek uczy używania konstruktorów i
new
-
this
odnosi się do nowego obiektu Niektórym podoba się sposób czytania.
Wady
Szczegóły instancji są wyciekające do wywołującego API (poprzez wymóg
new
), więc wszystkie wywołujące są ściśle powiązane z implementacją konstruktora. Jeśli kiedykolwiek potrzebujesz dodatkowej elastyczności fabrycznie, trzeba będzie refaktorować wszystkich rozmówców (co prawda wyjątkowego przypadku, a nie reguły).Zapominanie
new
jest tak częstym błędem, powinieneś zdecydowanie rozważyć dodanie sprawdzania boilerplate, aby upewnić się, że konstruktor jest poprawnie wywołany (if (!(this instanceof Foo)) { return new Foo() }
). EDIT: od ES6 (ES2015) nie można zapomniećnew
z konstruktoremclass
, albo konstruktor wyrzuci błąd.Jeśli wykonasz
instanceof
sprawdzenie, pozostawia niejasność, czynew
jest wymagane. Moim zdaniem nie powinno być. Skutecznie zwarłeśnew
wymóg, co oznacza, że możesz usunąć wadę # 1. Ale wtedy masz tylko funkcję fabryczną we wszystkich poza nazwą, z dodatkową płytą kotła, wielką literą i mniej elastycznym kontekstemthis
.
Konstruktory przełamują zasadę otwartą / zamkniętą
Ale moim głównym zmartwieniem jest to, że narusza to zasadę otwartą / zamkniętą. Zaczynasz eksportować konstruktor, użytkownicy zacznij używać konstruktora, a potem zdasz sobie sprawę, że potrzebujesz elastyczności fabryki (na przykład, aby zmienić implementację, aby użyć puli obiektów, utworzyć instancję w różnych kontekstach wykonawczych lub mieć większą elastyczność dziedziczenia przy użyciu prototypowego OO).
Ale utknąłeś. Nie możesz dokonać zmiany bez złamania całego kodu, który wywołuje twój konstruktor za pomocąnew
. Nie można przełączyć się na korzystanie z pul obiektów w celu zwiększenia wydajności, dla przykład.
Ponadto używanie konstruktorów daje zwodniczą instanceof
, która nie działa w kontekstach wykonawczych i nie działa, jeśli prototyp konstruktora zostanie zamieniony. Nie powiedzie się również, jeśli zaczniesz zwracać this
z konstruktora, a następnie przełączysz się na eksport dowolnego obiektu, co musisz zrobić, aby włączyć zachowanie fabryczne w konstruktorze.
Korzyści z korzystania z fabryk
Less code-no boilerplate wymagane.
Możesz zwrócić dowolny dowolny obiekt i użyć dowolnego prototypu-co daje większą elastyczność w tworzeniu różnych typów obiektów, które implementują ten sam API. Na przykład odtwarzacz multimedialny, który może tworzyć instancje odtwarzaczy HTML5 i flash, lub biblioteka 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 umożliwiać bardziej elastyczne prototypowanie modele dziedziczenia.
Nigdy nie będzie potrzeby konwersji z fabryki na konstruktora, więc refaktoryzacja nigdy nie będzie problemem.
Brak niejasności co do używania
new
. Nie. (to sprawi, żethis
będzie się źle zachowywać, patrz następny punkt).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ątrzplayer.create()
,this
odnosi się doplayer
, tak jak każde inne wywołanie metody.call
iapply
także resignthis
, zgodnie z oczekiwaniami. Jeśli przechowujesz prototypy w obiekcie nadrzędnym, może to być świetny sposób na dynamiczną wymianę funkcjonalności i włączenie bardzo elastycznego polimorfizmu dla instancji obiektu.Nie ma niejasności, czy kapitalizować. Nie. narzędzia Lint będą narzekać, a potem będziesz kuszony, aby spróbować użyć
new
, a następnie cofniesz opisaną powyżej korzyść.Niektórzy ludzie lubią drogę
var myFoo = foo();
lubvar myFoo = foo.create();
czyta.
Wady
new
nie zachowuje się zgodnie z oczekiwaniami(patrz wyżej). Rozwiązanie: nie używaj go.this
nie odnosi się do nowego obiektu (zamiast tego, jeśli konstruktor jest wywoływany z notacją kropkową lub nawiasem kwadratowym, np. foo.bar () -this
odnosi się dofoo
- podobnie jak każda inna metoda JavaScript -- patrz korzyści).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-24 18:34:38
Konstruktor zwraca instancję klasy, do której ją wywołujesz. Funkcja fabryczna może zwrócić wszystko. Można użyć funkcji fabrycznej, gdy trzeba zwrócić dowolne wartości lub gdy klasa ma duży proces konfiguracji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-02 08:24:44
Przykład funkcji konstruktora
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("Jack");
-
new
tworzy prototyp obiektuUser.prototype
i wywołujeUser
z wytworzonym obiektem jako jego wartościąthis
. -
new
traktuje wyrażenie argumentu dla jego operandu jako opcjonalne:let user = new User;
Spowoduje wywołanie
new
bez argumentów. -
new
zwraca utworzony obiekt , chyba że konstruktor Zwraca wartość obiektu, która jest zwracana w zamian. To jest wielkość krawędzi, która w większości przypadków może być ignorowana.
Plusy i minusy
Obiekty utworzone przez funkcje konstruktora dziedziczą właściwości z właściwości konstruktora prototype
i zwracają true używając operatora instanceOf
w funkcji konstruktora.
Powyższe zachowania mogą się nie udać, jeśli dynamicznie zmienisz wartość właściwości prototype
konstruktora po użyciu konstruktora. Jest to rzadkość i nie można tego zmienić, jeśli konstruktory zostały utworzone przy użyciu słowa kluczowego class
.
Funkcje konstruktora można rozszerzyć za pomocą słowa kluczowego extends
.
Funkcje konstruktora nie mogą zwracać null
jako wartości błędu. Ponieważ nie jest to obiektowy typ danych, jest ignorowany przez new
.
Przykład funkcji Fabrycznej
function User(name, age) {
return {
name,
age,
}
};
let user = User("Tom", 23);
Tutaj funkcja fabryczna jest wywoływana Bez new
. Funkcja jest całkowicie odpowiedzialna za bezpośrednie lub pośrednie użycie, jeśli jej argumenty i typ zwracanego obiektu. W tym przykład zwraca prosty obiekt [Object] z niektórymi właściwościami ustawionymi z argumentów.
Plusy i minusy
Łatwo ukrywa złożoność implementacji tworzenia obiektów przed wywołującym. Jest to szczególnie przydatne w przypadku funkcji kodu natywnego w przeglądarce.
Funkcja factory nie zawsze musi zwracać obiekty tego samego typu, A może nawet zwracać null
jako wskaźnik błędu.
W prostych przypadkach funkcje fabryczne mogą być proste w budowie i to znaczy.
Zwracane obiekty na ogół nie dziedziczą właściwości prototype
funkcji fabrycznej i zwracają false
z instanceOf factoryFunction
.
Funkcja factory nie może być bezpiecznie rozszerzona za pomocą słowa kluczowego extends
, ponieważ rozszerzone obiekty dziedziczyłyby z właściwości factory functions prototype
zamiast z właściwości prototype
konstruktora używanego przez funkcję factory.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55
Fabryki są "zawsze" lepsze. Jeśli używasz języków zorientowanych obiektowo, to
- zdecyduj o umowie (metody i co zrobią)
- tworzenie interfejsów, które ujawniają te metody (w javascript nie masz interfejsów, więc musisz wymyślić jakiś sposób sprawdzenia implementacji)
- Utwórz fabrykę, która zwróci implementację każdego wymaganego interfejsu.
Implementacje (rzeczywiste obiekty utworzone z new) nie są eksponowane użytkownikowi/konsumentowi fabrycznemu. Oznacza to, że deweloper fabryki może rozbudowywać i tworzyć nowe wdrożenia, o ile nie zerwie umowy...pozwala to fabrycznemu konsumentowi po prostu korzystać z nowego API bez konieczności zmiany kodu...jeśli użyli nowej i pojawi się "nowa" implementacja, to muszą przejść i zmienić każdą linię, która używa" nowej", aby użyć" nowej " implementacji...z fabryką ich Kod się nie zmienia...
Fabryki-lepsze niż Wszystko inne-spring framework jest całkowicie zbudowany wokół tego pomysłu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-09 11:14:38
Fabryki są warstwą abstrakcji i jak wszystkie abstrakcje mają. koszt w złożoności. W przypadku napotkania fabrycznego interfejsu API ustalenie, jaka jest fabryka danego interfejsu API, może być wyzwaniem dla konsumenta interfejsu API. Z konstruktorami odkrywalność jest trywialna.
Decydując się między ctors a fabrykami, musisz zdecydować, czy złożoność jest uzasadniona korzyścią.
Warto zauważyć, że konstruktory Javascript mogą być dowolne, zwracając coś innego niż to lub nieokreślone. Tak więc w js możesz uzyskać to, co najlepsze z obu światów-wykrywalne API i pooling / buforowanie obiektów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-07 02:52:42
Dla różnic, Eric Elliott wyjaśnił bardzo dobrze,
Ale na drugie pytanie:
Kiedy używać jednego zamiast drugiego?
Jeśli pochodzisz z tła zorientowanego obiektowo, funkcja konstruktora wygląda dla ciebie bardziej naturalnie.
w ten sposób nie zapomnij użyć słowa kluczowego new
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-16 11:34:00