module.exports vs. Exports w Node.js

725

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.exportsa exportsi dlatego oba są tu stosowane.

Andreas Köberle
źródło
81
Świetny zasób: hacksparrow.com/node-js-exports-vs-module-exports.html ^ _ ^
Naftali alias Neal
6
Zaktualizowano link „dla potomności”: nodejs.org/docs/latest/api/modules.html#modules_module_exports
Zeke
8
Chodzi o referencje. Pomyśl o eksportach jak o lokalnym obiekcie zmiennym wskazującym na module.exports. Jeśli zastąpisz wartość eksportu, utracisz odniesienie do module.exports, a module.exports ujawnisz jako interfejs publiczny.
Gabriel Llamas
14
Szybkie podsumowanie: zarówno exportsi module.exportspunkt do tego samego obiektu, chyba że ponownie przypisać jeden. I w końcu module.exportsjest zwracany. Jeśli więc zostaniesz ponownie przypisany exportsdo 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óry exportswskazywał na ...
Muhammad Umer

Odpowiedzi:

426

Ustawienie module.exportspozwala na database_modulewywołanie funkcji jak funkcji kiedy required. Proste ustawienie exportsnie pozwoli na eksport funkcji, ponieważ węzeł eksportuje module.exportsodwołania do obiektów . Poniższy kod nie pozwala użytkownikowi na wywołanie funkcji.

module.js

Poniższe nie będzie działać.

exports = nano = function database_module(cfg) {return;}

Poniższe będzie działać, jeśli module.exportsjest ustawione.

module.exports = exports = nano = function database_module(cfg) {return;}

konsola

var func = require('./module.js');
// the following line will **work** with module.exports
func();

Zasadniczo node.js nie eksportuje obiektu, który exportsobecnie się odwołuje, ale eksportuje właściwości tego, co exportspierwotnie się odwołuje. Mimo że Node.js eksportuje module.exportsodwołania do obiektów , pozwala to wywoływać je jak funkcję.


Drugi najmniej ważny powód

Określają one zarówno module.exportsi exportsdo zapewnienia exportsnie odwołuje uprzedniej eksportowany obiekt. Ustawiając oba, użyjesz exportsjako skrótu i ​​unikniesz potencjalnych błędów później.

Używanie exports.prop = true zamiast module.exports.prop = trueratuje postacie i pozwala uniknąć zamieszania.

Limonka
źródło
8
@ajostergaard: Tak się składa, że ​​jest to nazwa biblioteki, z której wzięto przykład OP. W module pozwala autorowi pisać rzeczy takie jak nano.version = '3.3'zamiast module.exports.version = '3.3', co czyta się nieco jaśniej. (Zauważ, że nanojest to zmienna lokalna, zadeklarowana nieco przed ustawieniem eksportu modułu ).
josh3736,
3
@ wapno - dzięki - cieszę się, że jest to w dużej mierze nieistotne, ponieważ gdyby tak nie było, oznaczałoby to, że całkowicie źle zrozumiałem. : - | :)
ostergaard
Hej, Lime, to dość stara odpowiedź, ale mam nadzieję, że możesz coś wyjaśnić. Gdybym miał ustawić, module.exportsale nie exports , czy mój kod nadal działałby? Dzięki za wszelką pomoc!
Asad Saeeduddin
1
@Asad Tak, funkcja wyeksportuje poprawnie, pod warunkiem, że ustawiłeśmodule.exports
Lime
@Liam dzięki za cenną odpowiedź. jeszcze kilka zapytań - na początku server.js, jakie są oczekiwane wartości module.exports i eksportów? czy moduł.exports ma być zerowy, a eksport ustawiony na pusty obiekt? Czy to jest dziedzictwo, czy istnieje jakikolwiek uzasadniony przypadek użycia do wskazania eksportu i modułu. Eksportu do dwóch różnych obiektów?
Sushil
504

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):

var module = new Module(...);
var exports = module.exports;

wprowadź opis zdjęcia tutaj

Więc cokolwiek zrobisz, pamiętaj o tym module.exportsi NIE exportszostanie ono zwrócone z twojego modułu, gdy będziesz potrzebować tego modułu z innego miejsca.

Więc kiedy robisz coś takiego:

exports.a = function() {
    console.log("a");
}
exports.b = function() {
    console.log("b");
}

Dodajesz 2 funkcję ai bdo obiektu, w którym module.exportsrównież punkty, więc typeofzwracanym wynikiem będzie object:{ a: [Function], b: [Function] }

Oczywiście jest to ten sam wynik, który otrzymasz, jeśli użyjesz module.exportsw tym przykładzie zamiast exports.

Jest tak w przypadku, gdy chcesz, module.exportsaby zachowywał się jak kontener eksportowanych wartości. Natomiast jeśli chcesz tylko wyeksportować funkcję konstruktora, jest coś, co powinieneś wiedzieć o używaniu module.exportslub exports; (Pamiętaj, że module.exportszostanie ono zwrócone, gdy będziesz czegoś potrzebować, a nie export).

module.exports = function Something() {
    console.log('bla bla');
}

Teraz typeofzwracany 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 exportsnie możesz użyć czegoś takiego:

exports = function Something() {
    console.log('bla bla');
}
var x = require('./file1.js')(); //Error: require is not a function

Ponieważ z exports, odwołanie nie wskazuje już na obiekcie, gdzie module.exportspunkty, więc nie jest to relacja pomiędzy exportsi module.exportsjuż. W tym przypadku module.exportsnadal wskazuje pusty obiekt, {}który zostanie zwrócony.

Pomocna odpowiedź z innego tematu powinna również pomóc: Czy JavaScript przechodzi przez referencję?

Srle
źródło
2
Dobre wyjaśnienie, ale nadal nie rozumiem, jak można całkowicie pominąć module.exportsmoduł, na przykład w tym npmpakiecie: github.com/tj/consolidate.js/blob/master/lib/consolidate.js
CodyBugstein
4
@Imray wyjaśnienie jest tutaj: Czy JavaScript przechodzi przez odniesienie? exports.a = function(){}; works, exports = function(){} doesn't work
około
29
oooo wreszcie ta odpowiedź to wyjaśnia. Zasadniczo eksport odnosi się do obiektu, do którego możesz dodać właściwości, ale jeśli ponownie przypisasz go do funkcji, nie będziesz już długo dołączać właściwości do tego oryginalnego obiektu. Teraz eksport odnosi się do funkcji, podczas gdy module.exports nadal wskazuje na ten obiekt i ponieważ jest on zwracany. Można powiedzieć, że eksport został w zasadzie śmieci wyrzucony.
Muhammad Umer
5
Więc jaki jest sens używania exports? Dlaczego nie zawsze używać, module.exportsjeśli jest to tylko zmiana przypisania? Wydaje mi się mylące.
jedd.ahyoung
1
@ jedd.ahyoung Pisanie jest mniej kłopotliwe exports.somethingzamiastmodule.exports.something
Srle
209

Zasadniczo odpowiedź leży w tym, co naprawdę dzieje się, gdy moduł jest wymagany za pomocą requireinstrukcji. Zakładając, że jest to pierwszy moduł, który jest wymagany.

Na przykład:

var x = require('file1.js');

zawartość pliku file1.js:

module.exports = '123';

Po wykonaniu powyższej instrukcji Moduletworzony jest obiekt. Jego funkcją konstruktora jest:

function Module(id, parent) {
    this.id = id;
    this.exports = {};
    this.parent = parent;
    if (parent && parent.children) {
        parent.children.push(this);
    }

    this.filename = null;
    this.loaded = false;
    this.children = [];
}

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:

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
});

I ta anonimowa funkcja jest wywoływana w następujący sposób, moduletutaj odnosi się do Moduleobiektu utworzonego wcześniej.

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
}) (module.exports,require, module, "path_to_file1.js","directory of the file1.js");

Jak widzimy wewnątrz funkcji, exportsformalny argument dotyczy module.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.

exports = module.exports = {};

Jeśli zrobimy to w niewłaściwy sposób , module.exportsnadal będziemy wskazywać na obiekt utworzony jako część instancji modułu.

exports = {};

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.

Chandu
źródło
8
Zgubiłeś mnie tutajexports = module.exports = {};
Giant Elk
2
Myślę, że to powinna być najlepsza odpowiedź, wyjaśnia, dlaczego func()nie udało się odpowiedzieć @ Williamowi!
turtledove
2
Nie widzę żadnej korzyści do dodania exports = module.exports = app;w ostatnim wierszu kodu. Wygląda na to, że module.exportszostanie wyeksportowany i nigdy go nie użyjemy exports, ponieważ znowu znajduje się w ostatnim wierszu kodu. Dlaczego więc nie dodamy po prostumodule.exports = app;
lvarayut
79

Początkowo module.exports=exports, a requirefunkcja zwraca obiekt module.exportsodwoł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.exportsto prawdziwy szef.

Cameron
źródło
1
Tak, to jest prawdziwa odpowiedź. Jest zwięzłe i jasne. Inni mogą mieć rację, ale mają pełne fantazji warunki i nie koncentrują się dokładnie na odpowiedzi na to pytanie.
Khoa
To zdecydowanie najczystsza odpowiedź! Jeśli chcesz dodać do zakładek, to jest dokładnie ten link: stackoverflow.com/questions/7137397/…
lambdarookie
56

exportsi module.exportssą takie same, chyba że zmienisz przypisanie exportsw module.

Najprostszym sposobem, aby o tym pomyśleć, jest przekonanie, że linia ta jest domyślnie na górze każdego modułu.

var exports = module.exports = {};

Jeśli w swoim module ponownie przypisujesz exports, to przypisujesz go ponownie w swoim module i nie jest już równy module.exports. Dlatego jeśli chcesz wyeksportować funkcję, musisz wykonać:

module.exports = function() { ... }

Jeśli po prostu przypisany swój function() { ... }TO exports, można byłoby realokacja exportsaby nie wskazywały już module.exports.

Jeśli nie chcesz za module.exportskażdym razem odwoływać się do swojej funkcji , możesz:

module.exports = exports = function() { ... }

Zauważ, że module.exportsjest to najbardziej lewy argument.

Dołączanie właściwości do exportsnie jest takie samo, ponieważ nie przypisujesz go ponownie. Właśnie dlatego to działa

exports.foo = function() { ... }
dustin.schultz
źródło
9
To było najłatwiejsze do zrozumienia spośród wszystkich odpowiedzi!
Adarsh ​​Konchady,
2
Ładne i proste
Fibono
1
Prosty i łatwiejszy sposób na zrozumienie tej funkcji.
FilipeCanatto
27

JavaScript przekazuje obiekty przez kopię odwołania

Jest to subtelna różnica w sposobie przekazywania obiektów przez referencję w JavaScript.

exportsi module.exportsoba wskazują na ten sam obiekt. exportsjest zmienną i module.exportsjest atrybutem obiektu modułu.

Powiedzmy, że piszę coś takiego:

exports = {a:1};
module.exports = {b:12};

exportsi module.exportsteraz 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}

superluminarny
źródło
6
Najlepsza odpowiedź imho!
Pan AJ
1
„JavaScript przechodzi przez odniesienie” - Nie.
xehpuk
13

Po prostu przeprowadzam test, okazuje się, że wewnątrz kodu modułu nodejsa powinno być coś takiego:

var module.exports = {};
var exports = module.exports;

więc:

1:

exports = function(){}; // this will not work! as it make the exports to some other pointer
module.exports = function(){}; // it works! cause finally nodejs make the module.exports to export.

2:

exports.abc = function(){}; // works!
exports.efg = function(){}; // works!

3: ale w tym przypadku

module.exports = function(){}; // from now on we have to using module.exports to attach more stuff to exports.
module.exports.a = 'value a'; // works
exports.b = 'value b'; // the b will nerver be seen cause of the first line of code we have do it before (or later)
Lyman Lai
źródło
Lyman, więc module.exportsto swego rodzaju „real-deal”, że węzeł gaśnie od ale w pewnym momencie trzeba dodać wszystkie exportssię module.exportschyba, że używasz exports.namespace(przypadek 2 powyżej), który w tym przypadku wydaje się być jak Węzeł uruchomił extends(module.exports, exports);dodawanie wszystkich „nazw” exportsdo module.exportsobiektu? Innymi słowy, jeśli używasz, exportsto prawdopodobnie chcesz ustawić na nim właściwości?
Cody
11

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:

module.exports = exports = db;
Salar
źródło
8

Przeszedłem kilka testów i myślę, że może to rzucić nieco światła na ten temat ...

app.js:

var ...
  , routes = require('./routes')
  ...;
...
console.log('@routes', routes);
...

wersje /routes/index.js:

exports = function fn(){}; // outputs "@routes {}"

exports.fn = function fn(){};  // outputs "@routes { fn: [Function: fn] }"

module.exports = function fn(){};  // outputs "@routes function fn(){}"

module.exports.fn = function fn(){};  // outputs "@routes { fn: [Function: fn] }"

Dodałem nawet nowe pliki:

./routes/index.js:

module.exports = require('./not-index.js');
module.exports = require('./user.js');

./routes/not-index.js:

exports = function fn(){};

./routes/user.js:

exports = function user(){};

Otrzymujemy wynik „@routes {}”


./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');

./routes/not-index.js:

exports = function fn(){};

./routes/user.js:

exports = function user(){};

Otrzymujemy wynik „@routes {fn: {}, użytkownik: {}}”


./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');

./routes/not-index.js:

exports.fn = function fn(){};

./routes/user.js:

exports.user = function user(){};

Otrzymujemy wynik „@routes {użytkownik: [Funkcja: użytkownik]}” Jeśli zmienimy user.jsna { ThisLoadedLast: [Function: ThisLoadedLast] }, otrzymamy wynik „@routes {ThisLoadedLast: [Function: ThisLoadedLast]}”.


Ale jeśli zmodyfikujemy ./routes/index.js...

./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.ThisLoadedLast = require('./user.js');

./routes/not-index.js:

exports.fn = function fn(){};

./routes/user.js:

exports.ThisLoadedLast = function ThisLoadedLast(){};

... otrzymujemy „@routes {fn: {fn: [Function: fn]}, ThisLoadedLast: {ThisLoadedLast: [Function: ThisLoadedLast]}}”

Proponuję więc zawsze używać module.exportsw 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

Cody
źródło
Myślę, że są niepotrzebnie skomplikowane i mylące. Powinien być przejrzysty i intuicyjny.
ngungo
Zgadzam się. Może to być przydatne, ponieważ przestrzeń nazw jest w pewnych okolicznościach, ale na ogół nie zamierza niczego tworzyć ani łamać.
Cody
4

To pokazuje, jak require()działa w najprostszej formie, zaczerpniętej z Eloquent JavaScript

Problem 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 exportsobiekt, który tworzy, był eksportowaną wartością.

Rozwiązanie Zapewnij modułom inną zmienną, modulektó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.

function require(name) {
  if (name in require.cache)
    return require.cache[name];
  var code = new Function("exports, module", readFile(name));
  var exports = {}, module = {exports: exports};
  code(exports, module);
  require.cache[name] = module.exports;
  return module.exports;
}
require.cache = Object.create(null);
onmyway133
źródło
Musiałem odtworzyć to w Węzle i przetestować kilka rzeczy, dopóki nie dostanę, ssę. Zasadniczo funkcja wewnętrzna utworzona dla modułu nigdy nawet nie zwraca obiektu eksportu. Zatem obiekt „eksportu” nie jest tak naprawdę przypisany w module, np. Jeśli spróbujesz napisać eksport = „to jest teraz ciąg znaków” bezpośrednio. Obiekt istnieje tylko jako odniesienie. To jest zachowanie, które nie wydaje mi się, że do tej pory właściwie to zrozumiałem.
danielgormly
4

Oto wynik

console.log("module:");
console.log(module);

console.log("exports:");
console.log(exports);

console.log("module.exports:");
console.log(module.exports);

wprowadź opis zdjęcia tutaj

Również:

if(module.exports === exports){
    console.log("YES");
}else{
    console.log("NO");
}

//YES

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.

serkan
źródło
4
var a = {},md={};

// Po pierwsze, eksporty i module.exports wskazują ten sam pusty Obiekt

exp = a;//exports =a;
md.exp = a;//module.exports = a;

exp.attr = "change";

console.log(md.exp);//{attr:"change"}

// Jeśli wskażesz exp na inny obiekt zamiast wskazać jego właściwość na inny obiekt. Plik md.exp będzie pusty Obiekt {}

var a ={},md={};
exp =a;
md.exp =a;

exp = function(){ console.log('Do nothing...'); };

console.log(md.exp); //{}
Anson Hwang
źródło
4

Z dokumentów

Zmienna eksportu jest dostępna w zakresie na poziomie pliku modułu i przypisuje się jej wartość module.exports przed oszacowaniem modułu.

Pozwala na skrót, dzięki czemu moduł.exports.f = ... można zapisać bardziej zwięźle jako exports.f = .... Należy jednak pamiętać, że jak każda zmienna, jeśli nowa wartość jest przypisana do eksportu, jest to nie jest już związany z module.exports:

Jest to po prostu zmienna wskazująca moduł.exports.

ANewGuyInTown
źródło
4

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

var exports = module.exports 

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

Sudhir Srinivasan
źródło
link git jest zepsuty
Jesse Hattabaugh
Link jest teraz naprawiony.
Paweł Gościcki,
3

„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

madKakoo
źródło
3

module.exportsi exportsoba 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ą requireinstrukcji. exportsto skrót udostępniony dla tej samej rzeczy. Na przykład:

module.exports.add = (a, b) => a+b

jest równoważne z pisaniem:

exports.add = (a, b) => a+b

Jest to w porządku, o ile nie przypisujesz nowej wartości exportszmiennej. Kiedy robisz coś takiego:

exports = (a, b) => a+b 

gdy przypisujesz mu nową wartość, exportsnie ma już odniesienia do wyeksportowanego obiektu, a zatem pozostanie lokalny dla twojego modułu.

Jeśli planujesz przypisać nową wartość module.exportszamiast dodawać nowe właściwości do udostępnionego obiektu początkowego, prawdopodobnie powinieneś rozważyć wykonanie poniższych czynności:

module.exports = exports = (a, b) => a+b

Witryna Node.js ma bardzo dobre wytłumaczenie tego.

Justin Pathrose Vareed
źródło
2

1. eksport -> użyj jako narzędzia singleton
2. eksport modułu -> użyj jako obiekty logiczne, takie jak usługa, model itp

riv
źródło
2

Stwórzmy jeden moduł na 2 sposoby:

Jednokierunkowa

var aa = {
    a: () => {return 'a'},
    b: () => {return 'b'}
}

module.exports = aa;

Drugi sposób

exports.a = () => {return 'a';}
exports.b = () => {return 'b';}

I w ten sposób metoda replace () zintegruje moduł.

Pierwszy sposób:

function require(){
    module.exports = {};
    var exports = module.exports;

    var aa = {
        a: () => {return 'a'},
        b: () => {return 'b'}
    }
    module.exports = aa;

    return module.exports;
}

Drugi sposób

function require(){
    module.exports = {};
    var exports = module.exports;

    exports.a = () => {return 'a';}
    exports.b = () => {return 'b';}

    return module.exports;
}
Dmitrij Siergiejew
źródło
2

dlaczego oba są tutaj używane

Wierzę, że oni po prostu chcą być jasne, że module.exports, exportsi nanowskazują na tę samą funkcję - pozwala użyć zmiennej do wywołania funkcji w pliku. nanozapewnia kontekst dla działania tej funkcji.

exportsnie zostaną wyeksportowane (tylko module.exportsbędą), więc po co też to nadpisywać?

Kompromis gadatliwości ogranicza ryzyko przyszłych błędów, takich jak użycie exportszamiast module.exportsw pliku. Zapewnia również wyjaśnienie, że module.exportsi exportsfaktycznie wskazują na tę samą wartość.


module.exports vs exports

Dopóki nie zmienisz przypisania module.exportslub exports(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ć, exportsaby 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.exportsbyć czymś konkretnym (np. Funkcją).

Ustawienie exportsna obiekt niebędący przedmiotem nie ma większego sensu, ponieważ będziesz musiał ustawić go module.exports = exportsna końcu, aby móc go używać w innych plikach.

let module = { exports: {} };
let exports = module.exports;

exports.msg = 'hi';
console.log(module.exports === exports); // true

exports = 'yo';
console.log(module.exports === exports); // false

exports = module.exports;
console.log(module.exports === exports); // true

module.exports = 'hello';
console.log(module.exports === exports); // false

module.exports = exports;
console.log(module.exports === exports); // true

Po co przypisywać module.exportsdo 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: let sayHello = require('./helloWorld1'); sayHello.hello; // hello world

helloWorld2.js: module.exports = () => console.log('hello world');

app2.js: let sayHello = require('./helloWorld2'); sayHello; // hello world

JBallin
źródło
2

wprowadź opis zdjęcia tutaj

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() => { ... } wtedy requirenigdzie w swojej aplikacji i wykorzystania ...

kontrolery / user.js

exports.findById = () => {
    //  do something
}

wymaga w pliku.j.j użycia:

const {findyId} = './controllers/user'
Ryan Dhungel
źródło
2

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:

 (function(exports, require, module, __filename, __dirname) {

 })()

Zauważ, że pierwszy parametr exportsjest pustym obiektem, a trzeci parametr modulejest obiektem o wielu właściwościach, a jedna z właściwości ma nazwę exports. To jest to, co exportspochodzi i co module.exportspochodzi. Pierwszy z nich jest obiektem zmiennym, a drugi jest własnością moduleobiektu.

W module Node.js automatycznie robi to na początku: module.exports = exportsi ostatecznie zwraca module.exports.

Możesz więc zobaczyć, że jeśli zmienisz przypisanie wartości exports, nie będzie to miało żadnego wpływu module.exports. (Po prostu dlatego, że exportswskazuje inny nowy obiekt, ale module.exportsnadal zawiera stary exports)

let exports = {};
const module = {};
module.exports = exports;

exports = { a: 1 }
console.log(module.exports) // {}

Ale jeśli zaktualizujesz właściwości exports, na pewno będzie to miało wpływ na module.exports. Ponieważ oba wskazują na ten sam obiekt.

let exports = {};
const module = {};
module.exports = exports;

exports.a = 1;
module.exports.b = 2;
console.log(module.exports) // { a: 1, b: 2 }

Zauważ również, że jeśli ponownie przypisasz inną wartość module.exports, nie będzie to miało znaczenia dla exportsaktualizacji. Każda aktualizacja exportsjest ignorowana, ponieważ module.exportswskazuje na inny obiekt.

let exports = {};
const module = {};
module.exports = exports;

exports.a = 1;
module.exports = {
  hello: () => console.log('hello')
}
console.log(module.exports) // { hello: () => console.log('hello')}
qinmu2127
źródło
0

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

'(function (exports, require, module, __filename, __dirname) {',+
     //your js file content
 '\n});'

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

console.log("module is "+Object.prototype.toString.call(module));
console.log("object.keys "+Object.keys(module));
console.log(module.exports);
console.log(exports === module.exports);
console.log("exports is "+Object.prototype.toString.call(exports));
console.log('----------------------------------------------');
var foo = require('a.js');
console.log("object.keys of foo: "+Object.keys(foo));
console.log('name is '+ foo);
foo();

skopiuj ten kod do a.js

exports.name = 'hello';
module.exports.name = 'hi';
module.exports.age = 23;
module.exports = function(){console.log('function to module exports')};
//exports = function(){console.log('function to export');}

teraz uruchom za pomocą węzła

to jest wynik

module is [object Object]
object.keys id,exports,parent,filename,loaded,children,paths
{}
true

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”.

sidias
źródło
0
  1. Oba module.exportsi exportswskazują na to samo function database_module(cfg) {...}.

    1| var a, b;
    2| a = b = function() { console.log("Old"); };
    3|     b = function() { console.log("New"); };
    4|
    5| a(); // "Old"
    6| b(); // "New"

    Możesz zmienić bw wierszu 3 na a, wyjście jest odwrotne. Z tego wniosek:

    ai bsą niezależni.

  2. module.exports = exports = nano = function database_module(cfg) {...}Jest więc równoważne z:

    var f = function database_module(cfg) {...};
    module.exports = f;
    exports = f;

    Zakłada się, że powyższe module.jsjest wymagane przez foo.js. Korzyści module.exports = exports = nano = function database_module(cfg) {...}są teraz oczywiste:

    • W foo.js, ponieważ module.exportsjest require('./module.js'):

      var output = require('./modules.js')();
    • W moduls.js: Możesz użyć exportszamiast module.exports.

Będziesz szczęśliwy, jeśli jedno exportsi drugie module.exportswskazuje na to samo.

Pada deszcz
źródło