Differenza tra "module.exports" ed "export" nel CommonJs Module System


288

In questa pagina ( http://docs.nodejitsu.com/articles/getting-started/what-is-require ), si afferma che "Se vuoi impostare l'oggetto di esportazione su una funzione o su un nuovo oggetto, devi utilizzare l'oggetto module.exports. "

La mia domanda è perché.

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

Ho consolato.logged il risultato ( result=require(example.js)) e il primo è [Function]il secondo {}.

Potresti per favore spiegare il motivo? Ho letto il post qui: module.exports vs esportazioni Node.js . È utile, ma non spiega il motivo per cui è stato progettato in questo modo. Ci saranno problemi se il riferimento delle esportazioni viene restituito direttamente?


11
Usa sempre module.exports.
Gabriel Llamas

1
Penso che seguire i consigli sopra menzionati permetta di evitare questo problema.
Vitalii Korsakov

@GabrielLlamas quindi perché molti pacchetti usano solo exports, ad esempio github.com/tj/consolidate.js/blob/master/lib/consolidate.js ?
CodyBugstein

3
@Imray Se si usa sempre module.exports, non sarete mai sbagliato, ma è possibile utilizzare exportsse non si sta sostituendo l'oggetto predefinito esportato, che è, se semplicemente collegare le proprietà in questo modo: var foo = require('foo').foo. Questa fooproprietà può essere esportata in questo modo: exports.foo = ...e ovviamente anche con module.exports. Si tratta di una scelta personale, ma Attualmente sto usando module.exportse exportsin modo appropriato.
Gabriel Llamas

Preferisco exports.myFunc = function () {} quindi non devo mantenere un elenco di esportazioni in fondo al file. Sembra più vicino alla pratica comune di esportazione quando dichiari in ES6.
SacWebDeveloper

Risposte:


642

moduleè un semplice oggetto JavaScript con una exportsproprietà. exportsè una semplice variabile JavaScript che sembra essere impostata su module.exports. Alla fine del file, node.js fondamentalmente "tornerà" module.exportsalla requirefunzione. Un modo semplificato per visualizzare un file JS in Node potrebbe essere questo:

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

// your code

return module.exports;

Se imposti una proprietà exports, ad esempio exports.a = 9;, verrà impostata module.exports.aanche quella perché gli oggetti vengono passati come riferimenti in JavaScript, il che significa che se imposti più variabili sullo stesso oggetto, sono tutti lo stesso oggetto; così allora exportse module.exportssono lo stesso oggetto.
Ma se imposti exportsqualcosa di nuovo, non sarà più impostato su module.exports, quindi exportse module.exportsnon sono più lo stesso oggetto.


13
Bene, sono solo le basi dei tipi di riferimento.
Vitalii Korsakov

21
Perché!? Perché si può leggere solo qui. Questo dovrebbe essere lo slogan per ogni javaScript modulare. Grazie
lima_fil

8
Splendidamente spiegato!
Aakash Verma

3
fantastica, migliore risposta !!
Giovanni

6
Ottima spiegazione. Anche la documentazione per lo module.exportsdescrive: nodejs.org/api/modules.html#modules_module_exports
Brian Morearty

58

La risposta di Renee è ben spiegata. Aggiunta alla risposta con un esempio:

Node fa molte cose al tuo file e una delle cose importanti è WRAPPING il tuo file. All'interno del codice sorgente di nodejs viene restituito "module.exports". Facciamo un passo indietro e comprendiamo l'involucro. Supponi di averlo fatto

saluto.js

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

module.exports = greet;

il codice sopra è racchiuso come IIFE (Espressione di funzione immediatamente invocata) all'interno del codice sorgente di nodejs come segue:

(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

e la funzione precedente viene invocata (.apply ()) e restituita module.exports. In questo momento module.exports ed export che puntano allo stesso riferimento.

Ora, immagina di riscrivere Greet.js come

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

l'uscita sarà

[Function]
{}

il motivo è: module.exports è un oggetto vuoto. Non abbiamo impostato nulla a module.exports, piuttosto abbiamo impostato export = function () ..... nel nuovo greet.js. Quindi, module.exports è vuoto.

Tecnicamente export e module.exports dovrebbero puntare allo stesso riferimento (è corretto !!). Ma usiamo "=" quando assegniamo function () .... alle esportazioni, che crea un altro oggetto nella memoria. Quindi, module.exports ed export producono risultati diversi. Quando si tratta di esportazioni, non possiamo ignorarlo.

Ora, immagina di riscrivere (questo si chiama Mutazione) greet.js (riferendosi alla risposta di Renee) come

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

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

l'uscita sarà

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

Come puoi vedere module.exports ed export puntano allo stesso riferimento che è una funzione. Se imposti una proprietà sulle esportazioni, verrà impostata su module.exports perché in JS gli oggetti vengono passati per riferimento.

La conclusione è sempre utilizzare module.exports per evitare confusione. Spero che sia di aiuto. Buona codifica :)


Anche questa è una bellissima risposta perspicace e completa la risposta di @ goto-bus-stop. :)
varun

26

Inoltre, una cosa che può aiutare a capire:

math.js

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

client.js

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

Ottimo, in questo caso:

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

Pertanto, per impostazione predefinita, "this" è effettivamente uguale a module.exports.

Tuttavia, se modifichi la tua implementazione in:

math.js

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

module.exports = {
    add: add
};

In questo caso, funzionerà bene, tuttavia, "this" non è più uguale a module.exports, perché è stato creato un nuovo oggetto.

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

E ora, ciò che verrà restituito da require è ciò che è stato definito all'interno di module.exports, non questo o più export.

Un altro modo per farlo sarebbe:

math.js

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

O:

math.js

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

15

La risposta di Rene sulla relazione tra exportse module.exportsè abbastanza chiara, si tratta di riferimenti javascript. Voglio solo aggiungere che:

Lo vediamo in molti moduli del nodo:

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

Questo assicurerà che anche se abbiamo modificato module.exports, possiamo ancora usare le esportazioni facendo in modo che queste due variabili puntino allo stesso oggetto.


Mi sono confuso con questa spiegazione, gentile da elaborare?
GuyFreakz

6
@GuyFreakz Non sono sicuro se questo parla la vostra confusione, ma module.exportse exportssono variabili appena separati, inizializzati per fare riferimento allo stesso oggetto. Se si modifica ciò a cui fa riferimento una variabile, le due variabili non fanno più riferimento alla stessa cosa. La riga di codice precedente garantisce che entrambe le variabili siano inizializzate sullo stesso nuovo oggetto.
Andrew Palmer

Un caso d'uso reale che tutti gli altri hanno perso su @fengshuo. Grazie!
Aakash Verma

0

myTest.js

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

exports.put = function () {};

console.log(module.exports)
// output: { get: [Function], put: [Function] }

exportse module.exportssono la stessa cosa e un riferimento allo stesso oggetto. Puoi aggiungere proprietà in entrambi i modi secondo la tua convenienza.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.