2013-05-05 14 views
174

Na tej stronie (http://docs.nodejitsu.com/articles/getting-started/what-is-require) stwierdza, że ​​"Jeśli chcesz ustawić obiekt eksportu do funkcji lub nowego obiektu, musisz użyć obiekt module.exports. "Różnica między "module.exports" i "exports" w systemie CommonJs Moduł

Moje pytanie brzmi: dlaczego?

// right 
module.exports = function() { 
    console.log("hello world") 
} 
// wrong 
exports = function() { 
    console.log("hello world") 
} 

I console.logged wyniku (result=require(example.js)), a pierwszy z nich jest [Function] drugi jest {}.

Czy mógłbyś wyjaśnić powód? Przeczytałem post tutaj: module.exports vs exports in Node.js. Jest pomocny, ale nie wyjaśnia przyczyny, dla której został zaprojektowany w ten sposób. Czy wystąpi problem, jeśli odniesienie do wywozu zostanie zwrócone bezpośrednio?

+4

Zawsze używaj 'module.exports'. –

+0

Myślę, że przestrzeganie powyższych wskazówek pozwala uniknąć tego problemu. –

+0

@GabrielLlamas, dlaczego więc wiele pakietów używa po prostu 'exports', na przykład https://github.com/tj/consolidate.js/blob/master/lib/consolidate.js? – CodyBugstein

Odpowiedz

421

module to zwykły obiekt JavaScript z właściwością exports. exports to zwykła zmienna JavaScript, która została ustawiona na module.exports. Na końcu pliku node.js w zasadzie "zwróci" module.exports do funkcji require. Uproszczony sposób aby plik JS w węźle może być to:

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

// your code 

return module.exports; 

Jeśli ustawisz właściwość na exports, jak exports.a = 9;, że ustawi module.exports.a jak dobrze ponieważ obiekty są przekazywane wokół jako odniesienia w JavaScript, co oznacza, że jeśli ustawisz wiele zmiennych do tego samego obiektu, to one są wszystkie tego samego obiektu; więc exports i module.exports są tym samym obiektem.
Ale jeśli ustawisz exports na coś nowego, nie będzie ono już ustawione na module.exports, więc exports i module.exports nie są już tym samym obiektem.

+6

Tak, to tylko podstawy typów referencyjnych. –

+4

Dlaczego? Dlaczego można to przeczytać tylko tutaj. Powinno to być mottem dla każdego modułowego javaScript. Dzięki –

13

Odpowiedź Rene na temat związku między exports a module.exports jest całkiem jasna, wszystko opiera się na odnośnikach do javascript. Tylko dodać, że:

Widzimy to w wielu modułów węzłów:

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

To będzie upewnić się, że nawet jeśli zmieniliśmy module.exports, możemy nadal korzystać z eksportu poprzez te dwie zmienne wskaż ten sam obiekt.

+0

Stałem się zdezorientowany tym wyjaśnieniem, uprzejmym do opracowania? – GuyFreakz

+3

@GuyFreakz Nie jestem pewien, czy to przemawia do twojego zamieszania, ale 'module.exports' i' exports' są tylko oddzielnymi zmiennymi, zainicjowanymi w celu odniesienia do tego samego obiektu. Jeśli zmienisz nazwę jednej zmiennej, dwie zmienne nie odwołują się do tej samej rzeczy. Linia kodu powyżej zapewnia, że ​​obie zmienne są inicjowane do tego samego nowego obiektu. –

+0

Rzeczywisty przypadek użycia, który wszyscy inni przegapili na @fengshuo. Dzięki! –

15

Również jeden rzeczy, które mogą pomóc zrozumieć:

math.js

this.add = function (a, b) { 
    return a + b; 
}; 

client.js

var math = require('./math'); 
console.log(math.add(2,2); // 4; 

wielki, w tym przypadku:

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

Tak więc domyślnie "to" i s faktycznie równa się module.exports.

Jeśli jednak zmienisz swoją implementację na:

matematyka.js

var add = function (a, b) { 
    return a + b; 
}; 

module.exports = { 
    add: add 
}; 

W tym przypadku będzie to działało w porządku, jednak „ten” nie jest równa module.exports więcej, ponieważ nowy obiekt został utworzony.

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

A teraz, co zostanie zwrócony przez require jest co zostało zdefiniowane wewnątrz module.exports, a nie to czy eksport, już.

Innym sposobem na to byłoby:

math.js

module.exports.add = function (a, b) { 
    return a + b; 
}; 

Albo:

math.js

exports.add = function (a, b) { 
    return a + b; 
}; 
22

odpowiedź Renee jest dobrze wyjaśnione. Dodatek do odpowiedzi na przykładzie:

Węzeł ma wiele rzeczy do pliku i jednym z ważniejszych jest WRAPOWANIE pliku. Wewnątrz nodejs zwracany jest kod źródłowy "module.exports". Zróbmy krok do tyłu i zrozumiemy opakowanie. Załóżmy, że masz

greet.js

var greet = function() { 
    console.log('Hello World'); 
}; 

module.exports = greet; 

powyższy kod jest owinięty jak Iife (Natychmiast Wykonano Expression Function) wewnątrz nodejs kodu źródłowego, co następuje:

(function (exports, require, module, __filename, __dirname) { //add by node 

     var greet = function() { 
     console.log('Hello World'); 
     }; 

     module.exports = greet; 

}).apply();             //add by node 

return module.exports;          //add by node 

i powyższa funkcja jest wywoływana (.apply()) i zwrócił moduł.exports. W tym czasie moduł wyeksportuje i eksportuje wskazując to samo odwołanie.

Teraz wyobraź sobie, że re-write greet.js jak

exports = function() { 
    console.log('Hello World'); 
}; 
console.log(exports); 
console.log(module.exports); 

wyjście będzie

[Function] 
{} 

powodem jest: module.exports jest pusty obiekt. Nie ustawiliśmy niczego w module.exports, a raczej ustawiamy exports = function() ..... w nowym pliku greet.js. Tak więc moduł.exports jest pusty.

Technicznie eksport i moduł.export powinien wskazywać na to samo odniesienie (to jest poprawne !!). Ale używamy "=" podczas przypisywania funkcji() .... do eksportu, co tworzy kolejny obiekt w pamięci. Tak więc moduł .exports i exports dają różne wyniki. Jeśli chodzi o eksport, nie możemy go przesłonić.

Teraz wyobraź sobie, że re-write (nazywa się to Mutacja) greet.js (odnosząc się do Renee odpowiedzi) jako

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

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

wyjście będzie

{ a: [Function] } 
{ a: [Function] } 

Jak widać module.exports i exports wskazują na to samo odwołanie, które jest funkcją. Jeśli ustawisz właściwość eksportu, to zostanie ustawiona na module.exports, ponieważ w JS obiekty są przekazywane przez odniesienie.

Wniosek jest zawsze używany module.exports, aby uniknąć nieporozumień. Mam nadzieję, że to pomoże. Szczęśliwe kodowanie :)

Powiązane problemy