Znalazłem następującą umowę w module Node.js:
module.exports = exports = nano = function database_module(cfg) {...}
Zastanawiam się, co jest różnica między module.exports
a exports
i dlatego oba są tu stosowane.
javascript
node.js
commonjs
Andreas Köberle
źródło
źródło
exports
imodule.exports
punkt do tego samego obiektu, chyba że ponownie przypisać jeden. I w końcumodule.exports
jest zwracany. Jeśli więc zostaniesz ponownie przypisanyexports
do funkcji, nie oczekuj funkcji, ponieważ nie będzie ona zwracana. Jeśli jednak przypisałeś taką funkcję,exports.func = function...
wynikowa rzecz miałaby właściwość func z funkcją jako wartością. Ponieważ dodałeś właściwość do obiektu, któryexports
wskazywał na ...Odpowiedzi:
Ustawienie
module.exports
pozwala nadatabase_module
wywołanie funkcji jak funkcji kiedyrequired
. Proste ustawienieexports
nie pozwoli na eksport funkcji, ponieważ węzeł eksportujemodule.exports
odwołania do obiektów . Poniższy kod nie pozwala użytkownikowi na wywołanie funkcji.module.js
Poniższe nie będzie działać.
Poniższe będzie działać, jeśli
module.exports
jest ustawione.konsola
Zasadniczo node.js nie eksportuje obiektu, który
exports
obecnie się odwołuje, ale eksportuje właściwości tego, coexports
pierwotnie się odwołuje. Mimo że Node.js eksportujemodule.exports
odwołania do obiektów , pozwala to wywoływać je jak funkcję.Drugi najmniej ważny powód
Określają one zarówno
module.exports
iexports
do zapewnieniaexports
nie odwołuje uprzedniej eksportowany obiekt. Ustawiając oba, użyjeszexports
jako skrótu i unikniesz potencjalnych błędów później.Używanie
exports.prop = true
zamiastmodule.exports.prop = true
ratuje postacie i pozwala uniknąć zamieszania.źródło
nano.version = '3.3'
zamiastmodule.exports.version = '3.3'
, co czyta się nieco jaśniej. (Zauważ, żenano
jest to zmienna lokalna, zadeklarowana nieco przed ustawieniem eksportu modułu ).module.exports
ale nieexports
, czy mój kod nadal działałby? Dzięki za wszelką pomoc!module.exports
Mimo że odpowiedź na pytanie została udzielona i zaakceptowana dawno temu, chcę tylko podzielić się moimi 2 centami:
Możesz sobie wyobrazić, że na samym początku pliku jest coś takiego (tylko dla wyjaśnienia):
Więc cokolwiek zrobisz, pamiętaj o tym
module.exports
i NIEexports
zostanie ono zwrócone z twojego modułu, gdy będziesz potrzebować tego modułu z innego miejsca.Więc kiedy robisz coś takiego:
Dodajesz 2 funkcję
a
ib
do obiektu, w którymmodule.exports
również punkty, więctypeof
zwracanym wynikiem będzieobject
:{ a: [Function], b: [Function] }
Oczywiście jest to ten sam wynik, który otrzymasz, jeśli użyjesz
module.exports
w tym przykładzie zamiastexports
.Jest tak w przypadku, gdy chcesz,
module.exports
aby zachowywał się jak kontener eksportowanych wartości. Natomiast jeśli chcesz tylko wyeksportować funkcję konstruktora, jest coś, co powinieneś wiedzieć o używaniumodule.exports
lubexports
; (Pamiętaj, żemodule.exports
zostanie ono zwrócone, gdy będziesz czegoś potrzebować, a nieexport
).Teraz
typeof
zwracany jest wynik'function'
i możesz go zażądać i natychmiast wywołać jak:var x = require('./file1.js')();
ponieważ nadpisujesz zwracany wynik jako funkcję.Jednak używając
exports
nie możesz użyć czegoś takiego:Ponieważ z
exports
, odwołanie nie wskazuje już na obiekcie, gdziemodule.exports
punkty, więc nie jest to relacja pomiędzyexports
imodule.exports
już. W tym przypadkumodule.exports
nadal wskazuje pusty obiekt,{}
który zostanie zwrócony.Pomocna odpowiedź z innego tematu powinna również pomóc: Czy JavaScript przechodzi przez referencję?
źródło
module.exports
moduł, na przykład w tymnpm
pakiecie: github.com/tj/consolidate.js/blob/master/lib/consolidate.jsexports.a = function(){}; works, exports = function(){} doesn't work
exports
? Dlaczego nie zawsze używać,module.exports
jeśli jest to tylko zmiana przypisania? Wydaje mi się mylące.exports.something
zamiastmodule.exports.something
Zasadniczo odpowiedź leży w tym, co naprawdę dzieje się, gdy moduł jest wymagany za pomocą
require
instrukcji. Zakładając, że jest to pierwszy moduł, który jest wymagany.Na przykład:
zawartość pliku file1.js:
Po wykonaniu powyższej instrukcji
Module
tworzony jest obiekt. Jego funkcją konstruktora jest:Jak widać, każdy obiekt modułu ma właściwość o nazwie
exports
. To jest ostatecznie zwracane jako częśćrequire
.Następnym krokiem wymagania jest zawinięcie zawartości pliku file1.js w anonimową funkcję, taką jak poniżej:
I ta anonimowa funkcja jest wywoływana w następujący sposób,
module
tutaj odnosi się doModule
obiektu utworzonego wcześniej.Jak widzimy wewnątrz funkcji,
exports
formalny argument dotyczymodule.exports
. Zasadniczo jest to wygoda dla programisty modułów.Jednak z tej wygody należy korzystać ostrożnie. W każdym razie, jeśli próbujesz przypisać nowy obiekt do eksportu, upewnij się, że robimy to w ten sposób.
Jeśli zrobimy to w niewłaściwy sposób ,
module.exports
nadal będziemy wskazywać na obiekt utworzony jako część instancji modułu.W rezultacie dodanie czegokolwiek do powyższego obiektu eksportu nie będzie miało wpływu na obiekt module.exports i nic nie zostanie wyeksportowane ani zwrócone jako część wymagania.
źródło
exports = module.exports = {};
func()
nie udało się odpowiedzieć @ Williamowi!exports = module.exports = app;
w ostatnim wierszu kodu. Wygląda na to, żemodule.exports
zostanie wyeksportowany i nigdy go nie użyjemyexports
, ponieważ znowu znajduje się w ostatnim wierszu kodu. Dlaczego więc nie dodamy po prostumodule.exports = app;
Początkowo
module.exports=exports
, arequire
funkcja zwraca obiektmodule.exports
odwołuje.jeśli dodamy właściwość do obiektu, powiedzmy
exports.a=1
, wtedy moduł.eksport i eksport nadal odnoszą się do tego samego obiektu. Jeśli więc wywołamy wymaganie i przypiszemy moduł do zmiennej, wówczas zmienna ma właściwość a, a jej wartość wynosi 1;Ale jeśli zastąpić jednego z nich, na przykład
exports=function(){}
, to są różni teraz: eksport odnosi się do nowego obiektu i module.exports odnoszą się do oryginalnego obiektu. A jeśli potrzebujemy pliku, nie zwróci on nowego obiektu, ponieważ module.exports nie odnosi się do nowego obiektu.Dla mnie będę dodawał nową właściwość lub zastąpię obie z nich do nowego obiektu. Zastąpienie jednego nie jest właściwe. I pamiętaj, że
module.exports
to prawdziwy szef.źródło
exports
imodule.exports
są takie same, chyba że zmienisz przypisanieexports
w module.Najprostszym sposobem, aby o tym pomyśleć, jest przekonanie, że linia ta jest domyślnie na górze każdego modułu.
Jeśli w swoim module ponownie przypisujesz
exports
, to przypisujesz go ponownie w swoim module i nie jest już równymodule.exports
. Dlatego jeśli chcesz wyeksportować funkcję, musisz wykonać:Jeśli po prostu przypisany swój
function() { ... }
TOexports
, można byłoby realokacjaexports
aby nie wskazywały jużmodule.exports
.Jeśli nie chcesz za
module.exports
każdym razem odwoływać się do swojej funkcji , możesz:Zauważ, że
module.exports
jest to najbardziej lewy argument.Dołączanie właściwości do
exports
nie jest takie samo, ponieważ nie przypisujesz go ponownie. Właśnie dlatego to działaźródło
JavaScript przekazuje obiekty przez kopię odwołania
Jest to subtelna różnica w sposobie przekazywania obiektów przez referencję w JavaScript.
exports
imodule.exports
oba wskazują na ten sam obiekt.exports
jest zmienną imodule.exports
jest atrybutem obiektu modułu.Powiedzmy, że piszę coś takiego:
exports
imodule.exports
teraz wskazują na różne obiekty. Modyfikowanie eksportów nie modyfikuje już modułów.eksportów.Gdy funkcja importu sprawdza
module.exports
, robi się{b:12}
źródło
Po prostu przeprowadzam test, okazuje się, że wewnątrz kodu modułu nodejsa powinno być coś takiego:
więc:
1:
2:
3: ale w tym przypadku
źródło
module.exports
to swego rodzaju „real-deal”, że węzeł gaśnie od ale w pewnym momencie trzeba dodać wszystkieexports
sięmodule.exports
chyba, że używaszexports.namespace
(przypadek 2 powyżej), który w tym przypadku wydaje się być jak Węzeł uruchomiłextends(module.exports, exports);
dodawanie wszystkich „nazw”exports
domodule.exports
obiektu? Innymi słowy, jeśli używasz,exports
to prawdopodobnie chcesz ustawić na nim właściwości?Oto dobry opis na temat modułów węzłów w node.js w książce akcji z publikacji Manninga .
To, co ostatecznie zostanie wyeksportowane do Twojej aplikacji, to module.exports.
eksport jest konfigurowany po prostu jako globalne odwołanie do module.exports , który początkowo jest definiowany jako pusty obiekt, do którego można dodawać właściwości. Więc exports.myFunc jest po prostu skrótem dla module.exports.myFunc .
W rezultacie, jeśli eksport ustawiony jest na cokolwiek innego, przerywa to odniesienie między module.exports a export . Ponieważ module.exportsto, co naprawdę jest eksportowane, eksport nie będzie już działał zgodnie z oczekiwaniami - nie odwołuje się już do modułu .exports . Jeśli chcesz utrzymać ten związek, można dokonać module.exports odwoływać eksportu ponownie w następujący sposób:
źródło
Przeszedłem kilka testów i myślę, że może to rzucić nieco światła na ten temat ...
app.js
:wersje
/routes/index.js
:Dodałem nawet nowe pliki:
./routes/index.js
:./routes/not-index.js
:./routes/user.js
:Otrzymujemy wynik „@routes {}”
./routes/index.js
:./routes/not-index.js
:./routes/user.js
:Otrzymujemy wynik „@routes {fn: {}, użytkownik: {}}”
./routes/index.js
:./routes/not-index.js
:./routes/user.js
:Otrzymujemy wynik „@routes {użytkownik: [Funkcja: użytkownik]}” Jeśli zmienimy
user.js
na{ ThisLoadedLast: [Function: ThisLoadedLast] }
, otrzymamy wynik „@routes {ThisLoadedLast: [Function: ThisLoadedLast]}”.Ale jeśli zmodyfikujemy
./routes/index.js
..../routes/index.js
:./routes/not-index.js
:./routes/user.js
:... otrzymujemy „@routes {fn: {fn: [Function: fn]}, ThisLoadedLast: {ThisLoadedLast: [Function: ThisLoadedLast]}}”
Proponuję więc zawsze używać
module.exports
w definicjach modułów.Nie do końca rozumiem, co się dzieje wewnętrznie z Node, ale proszę o komentarz, jeśli możesz to lepiej zrozumieć, ponieważ jestem pewien, że to pomaga.
- Szczęśliwego kodowania
źródło
To pokazuje, jak
require()
działa w najprostszej formie, zaczerpniętej z Eloquent JavaScriptProblem Moduł nie może bezpośrednio wyeksportować wartości innej niż obiekt eksportu, taki jak funkcja. Na przykład moduł może chcieć wyeksportować tylko konstruktor zdefiniowanego przez siebie typu obiektu. W tej chwili nie może tego zrobić, ponieważ polecenie wymaga zawsze, aby
exports
obiekt, który tworzy, był eksportowaną wartością.Rozwiązanie Zapewnij modułom inną zmienną,
module
która jest obiektem posiadającym właściwośćexports
. Ta właściwość początkowo wskazuje pusty obiekt utworzony przez wymaganie, ale można go zastąpić inną wartością w celu wyeksportowania czegoś innego.źródło
Oto wynik
Również:
Uwaga: Specyfikacja CommonJS zezwala jedynie na użycie zmiennej export do ujawnienia członków publicznych. Dlatego nazwany wzorzec eksportu jest jedynym, który jest naprawdę zgodny ze specyfikacją CommonJS. Zastosowanie module.exports jest rozszerzeniem dostarczonym przez Node.js do obsługi szerszego zakresu wzorców definicji modułów.
źródło
// Po pierwsze, eksporty i module.exports wskazują ten sam pusty Obiekt
// Jeśli wskażesz exp na inny obiekt zamiast wskazać jego właściwość na inny obiekt. Plik md.exp będzie pusty Obiekt {}
źródło
Z dokumentów
Jest to po prostu zmienna wskazująca moduł.exports.
źródło
Uważam, że ten link jest przydatny do odpowiedzi na powyższe pytanie.
http://timnew.me/blog/2012/04/20/exports-vs-module-exports-in-node-js/
Aby dodać do innych postów System modułu w węźle robi
przed wykonaniem kodu. Więc jeśli chcesz eksportować = foo, prawdopodobnie chcesz zrobić module.exports = eksport = foo, ale używając exports.foo = foo powinno być w porządku
źródło
„Jeśli chcesz, aby katalog główny eksportu modułu był funkcją (taką jak konstruktor) lub jeśli chcesz eksportować pełny obiekt w jednym przydziale zamiast budować jedną właściwość na raz, przypisz go do module.exports zamiast eksport ”. - http://nodejs.org/api/modules.html
źródło
module.exports
iexports
oba wskazują ten sam obiekt, zanim moduł zostanie oceniony.Każda właściwość dodana do
module.exports
obiektu będzie dostępna, gdy moduł będzie używany w innym module za pomocąrequire
instrukcji.exports
to skrót udostępniony dla tej samej rzeczy. Na przykład:jest równoważne z pisaniem:
Jest to w porządku, o ile nie przypisujesz nowej wartości
exports
zmiennej. Kiedy robisz coś takiego:gdy przypisujesz mu nową wartość,
exports
nie ma już odniesienia do wyeksportowanego obiektu, a zatem pozostanie lokalny dla twojego modułu.Jeśli planujesz przypisać nową wartość
module.exports
zamiast dodawać nowe właściwości do udostępnionego obiektu początkowego, prawdopodobnie powinieneś rozważyć wykonanie poniższych czynności:Witryna Node.js ma bardzo dobre wytłumaczenie tego.
źródło
1. eksport -> użyj jako narzędzia singleton
2. eksport modułu -> użyj jako obiekty logiczne, takie jak usługa, model itp
źródło
Stwórzmy jeden moduł na 2 sposoby:
Jednokierunkowa
Drugi sposób
I w ten sposób metoda replace () zintegruje moduł.
Pierwszy sposób:
Drugi sposób
źródło
Wierzę, że oni po prostu chcą być jasne, że
module.exports
,exports
inano
wskazują na tę samą funkcję - pozwala użyć zmiennej do wywołania funkcji w pliku.nano
zapewnia kontekst dla działania tej funkcji.exports
nie zostaną wyeksportowane (tylkomodule.exports
będą), więc po co też to nadpisywać?Kompromis gadatliwości ogranicza ryzyko przyszłych błędów, takich jak użycie
exports
zamiastmodule.exports
w pliku. Zapewnia również wyjaśnienie, żemodule.exports
iexports
faktycznie wskazują na tę samą wartość.module.exports
vsexports
Dopóki nie zmienisz przypisania
module.exports
lubexports
(i zamiast tego dodasz wartości do obiektu, do którego oba się odnoszą), nie będziesz mieć żadnych problemów i możesz bezpiecznie użyć,exports
aby być bardziej zwięzłym.Przypisując któryś z obiektów niebędących obiektami, wskazują one teraz różne miejsca, które mogą być mylące, chyba że celowo chcesz
module.exports
być czymś konkretnym (np. Funkcją).Ustawienie
exports
na obiekt niebędący przedmiotem nie ma większego sensu, ponieważ będziesz musiał ustawić gomodule.exports = exports
na końcu, aby móc go używać w innych plikach.Po co przypisywać
module.exports
do funkcji?Bardziej zwięzłe! Porównaj, o ile krótszy jest drugi przykład:
helloWorld1.js:module.exports.hello = () => console.log('hello world');
app1.js:
helloWorld2.js:let sayHello = require('./helloWorld1'); sayHello.hello; // hello world
module.exports = () => console.log('hello world');
app2.js:
let sayHello = require('./helloWorld2'); sayHello; // hello world
źródło
Każdy tworzony plik jest modułem. moduł jest obiektem. Ma
exports : {}
domyślnie właściwość o nazwie pusty obiekt.można tworzyć funkcje / middleware i dodać do tej pustej eksportu obiektów, takich jak
exports.findById() => { ... }
wtedyrequire
nigdzie w swojej aplikacji i wykorzystania ...kontrolery / user.js
wymaga w pliku.j.j użycia:
źródło
Aby zrozumieć różnice, musisz najpierw zrozumieć, co Node.js robi z każdym modułem w czasie wykonywania. Node.js tworzy funkcję otoki dla każdego modułu:
Zauważ, że pierwszy parametr
exports
jest pustym obiektem, a trzeci parametrmodule
jest obiektem o wielu właściwościach, a jedna z właściwości ma nazwęexports
. To jest to, coexports
pochodzi i comodule.exports
pochodzi. Pierwszy z nich jest obiektem zmiennym, a drugi jest własnościąmodule
obiektu.W module Node.js automatycznie robi to na początku:
module.exports = exports
i ostatecznie zwracamodule.exports
.Możesz więc zobaczyć, że jeśli zmienisz przypisanie wartości
exports
, nie będzie to miało żadnego wpływumodule.exports
. (Po prostu dlatego, żeexports
wskazuje inny nowy obiekt, alemodule.exports
nadal zawiera staryexports
)Ale jeśli zaktualizujesz właściwości
exports
, na pewno będzie to miało wpływ namodule.exports
. Ponieważ oba wskazują na ten sam obiekt.Zauważ również, że jeśli ponownie przypisasz inną wartość
module.exports
, nie będzie to miało znaczenia dlaexports
aktualizacji. Każda aktualizacjaexports
jest ignorowana, ponieważmodule.exports
wskazuje na inny obiekt.źródło
w pliku node.js plik module.js służy do uruchomienia modułu.load system. za każdym razem, gdy węzeł wykonuje plik, zawija zawartość pliku js w następujący sposób
ze względu na to zawijanie w kodzie źródłowym ur js można uzyskać dostęp do eksportu, wymagania, modułu itp. Podejście to jest stosowane, ponieważ nie ma innego sposobu na przeniesienie funkcjonalności pliku js do innego.
następnie węzeł wykonuje tę zawiniętą funkcję za pomocą c ++. w tym momencie obiekt eksportu, który przeszedł do tej funkcji, zostanie wypełniony.
możesz zobaczyć wewnątrz tej funkcji eksportu parametrów i modułu. w rzeczywistości eksport jest publicznym członkiem funkcji konstruktora modułów.
spójrz na następujący kod
skopiuj ten kod do b.js
skopiuj ten kod do a.js
teraz uruchom za pomocą węzła
to jest wynik
eksport jest [obiekt Obiekt]
object.keys of foo: name is function () {console.log ('funkcja do eksportu modułów')} funkcja do eksportu modułów
teraz usuń komentowany wiersz w a.js i skomentuj wiersz powyżej tego wiersza, usuń ostatni wiersz b.js i uruchom.
w świecie javascript nie można ponownie przypisać obiektu przekazanego jako parametr, ale można zmienić członka publicznego funkcji, gdy obiekt tej funkcji ustawiony jako parametr na inną funkcję
pamiętam
używaj module.exports i tylko jeśli chcesz uzyskać funkcję, gdy używasz słowa kluczowego wymaganego. w powyższym przykładzie zmienimy foo = wymagany (a.js); widać, że możemy wywołać foo jako funkcję;
tak wyjaśnia to dokumentacja węzła „Obiekt eksportu jest tworzony przez system Module. Czasami jest to niedopuszczalne, wielu chce, aby jego moduł był instancją jakiejś klasy. Aby to zrobić, przypisz żądany obiekt eksportu do module.exports”.
źródło
Możesz zmienić
b
w wierszu 3 naa
, wyjście jest odwrotne. Z tego wniosek:module.exports = exports = nano = function database_module(cfg) {...}
Jest więc równoważne z:Zakłada się, że powyższe
module.js
jest wymagane przezfoo.js
. Korzyścimodule.exports = exports = nano = function database_module(cfg) {...}
są teraz oczywiste:W
foo.js
, ponieważmodule.exports
jestrequire('./module.js')
:W
moduls.js
: Możesz użyćexports
zamiastmodule.exports
.Będziesz szczęśliwy, jeśli jedno
exports
i drugiemodule.exports
wskazuje na to samo.źródło