Qual è lo scopo di Node.js module.exports e come lo usi?


1432

Qual è lo scopo di Node.js module.exports e come lo usi?

Non riesco a trovare alcuna informazione al riguardo, ma sembra essere una parte piuttosto importante di Node.js come spesso la vedo nel codice sorgente.

Secondo la documentazione di Node.js :

modulo

Un riferimento alla corrente module. In particolare module.exports è uguale all'oggetto export. Vedi src/node.jsper maggiori informazioni.

Ma questo non aiuta davvero.

Cosa fa esattamente module.exportse quale sarebbe un semplice esempio?

Risposte:


1590

module.exportsè l'oggetto che viene effettivamente restituito a seguito di una requirechiamata.

La exportsvariabile è impostata inizialmente a quello stesso oggetto (vale a dire che è una scorciatoia "alias"), quindi nel codice del modulo si farebbe qualcosa di solito scrivere in questo modo:

let myFunc1 = function() { ... };
let myFunc2 = function() { ... };
exports.myFunc1 = myFunc1;
exports.myFunc2 = myFunc2;

per esportare (o "esporre") le funzioni con ambito interno myFunc1e myFunc2.

E nel codice chiamante useresti:

const m = require('./mymodule');
m.myFunc1();

dove l'ultima riga mostra come il risultato di require(di solito) sia solo un oggetto semplice le cui proprietà sono accessibili.

NB: se si sovrascrive exports, non si farà più riferimento module.exports. Quindi, se si desidera assegnare un nuovo oggetto (o un riferimento di funzione), exportsè necessario assegnare anche quel nuovo oggettomodule.exports


Vale la pena notare che il nome aggiunto exportsall'oggetto non deve essere uguale al nome con ambito interno del modulo per il valore che stai aggiungendo, quindi potresti avere:

let myVeryLongInternalName = function() { ... };
exports.shortName = myVeryLongInternalName;
// add other objects, functions, as required

seguito da:

const m = require('./mymodule');
m.shortName(); // invokes module.myVeryLongInternalName

119
Buona risposta - mi sembra che "esporre" sarebbe stata una scelta della terminologia migliore rispetto a "esportazioni"
UpTheCreek

2
@ApopheniaOverload: è possibile eseguire "exports.func1, exports.func2, ecc" per avere più metodi esposti da un unico file.
hellatan

73
Il modulo richiede dovrebbe essere var m = require ('./ mymodule'); , con il punto e la barra. In questo modo Node.js sa che stiamo usando un modulo locale.
Gui Premonsa,

7
Assicurati di usare: richiedi ('./ nome_modulo') perché potrebbe esserci qualche altro modulo node.js con un certo nome e invece di scegliere il tuo modulo, prenderà quello installato con node.js
Sazid,

3
@UpTheCreek esiste una lunga tradizione di riferimento ai simboli pubblici esposti da un modulo come "esportati", che risale a molti sistemi di programmazione e decenni. Questo non era un nuovo termine inventato dagli sviluppatori Node.
Mark Reed,

218

È già stata data una risposta, ma volevo aggiungere alcuni chiarimenti ...

Puoi usare entrambi exportse module.exportsper importare il codice nella tua applicazione in questo modo:

var mycode = require('./path/to/mycode');

Il caso d'uso di base che vedrai (ad es. Nel codice di esempio ExpressJS) è che imposti le proprietà exportssull'oggetto in un file .js che poi importi usandorequire()

Quindi, in un semplice esempio di conteggio, potresti avere:

(counter.js):

var count = 1;

exports.increment = function() {
    count++;
};

exports.getCount = function() {
    return count;
};

... quindi nella tua applicazione (web.js o qualsiasi altro file .js):

var counting = require('./counter.js');

console.log(counting.getCount()); // 1
counting.increment();
console.log(counting.getCount()); // 2

In termini semplici, puoi pensare ai file richiesti come funzioni che restituiscono un singolo oggetto e puoi aggiungere proprietà (stringhe, numeri, matrici, funzioni, qualsiasi cosa) all'oggetto che viene restituito impostandole exports.

A volte vorrai che l'oggetto restituito da una require()chiamata sia una funzione che puoi chiamare, piuttosto che un oggetto con proprietà. In tal caso devi anche impostare module.exports, in questo modo:

(sayhello.js):

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

(App.js):

var sayHello = require('./sayhello.js');
sayHello(); // "Hello World!"

La differenza tra export e module.exports è spiegata meglio in questa risposta qui .


come posso chiamare richiedere un modulo da un'altra cartella che non ha la cartella principale come la mia?
Igal,

@ user301639 è possibile utilizzare percorsi relativi per attraversare la gerarchia del file system. requireinizia relativamente alla cartella in cui esegui node app.js. Ti consiglio di pubblicare una nuova domanda con codice esplicito + esempi di struttura di cartelle per ottenere una risposta più chiara.
Jed Watson,

1
Ho dovuto modificare il tuo esempio di module.exports per farlo funzionare. file: var sayHello = require('./ex6_module.js'); console.log(sayHello());e modulo:module.exports = exports = function() { return "Hello World!"; }
Jason Lydon il

1
Ho trovato l'esempio dell'incremento davvero buono e l'ho usato per rinfrescare la mia mente ogni volta che mi sovraccarico di quello che sto facendo con le esportazioni.
Munkee,

module.exports = exports = function(){...}la seconda exportsè solo una variabile, giusto? In altre parole, può esseremodule.exports = abc = function()
Jeb50

60

Si noti che il meccanismo del modulo NodeJS si basa su moduli CommonJS che sono supportati in molte altre implementazioni come RequireJS , ma anche SproutCore , CouchDB , Wakanda , OrientDB , ArangoDB , RingoJS , TeaJS , SilkJS , curl.js o persino Adobe Photoshop (tramite PSLib ). Puoi trovare l'elenco completo delle implementazioni conosciute qui .

A meno che il tuo modulo non utilizzi funzionalità o moduli specifici del nodo, ti consiglio vivamente di utilizzare exportsinvece di quello module.exports che non fa parte dello standard CommonJS , e quindi per lo più non supportato da altre implementazioni.

Un'altra caratteristica specifica di NodeJS è quando si assegna un riferimento a un nuovo oggetto exportsinvece di aggiungere proprietà e metodi ad esso come nell'ultimo esempio fornito da Jed Watson in questo thread. Scoraggerei personalmente questa pratica poiché interrompe il supporto di riferimento circolare del meccanismo dei moduli CommonJS. Quindi non è supportato da tutte le implementazioni e l'esempio Jed dovrebbe essere scritto in questo modo (o uno simile) per fornire un modulo più universale:

(sayhello.js):

exports.run = function() {
    console.log("Hello World!");
}

(App.js):

var sayHello = require('./sayhello');
sayHello.run(); // "Hello World!"

O usando le funzionalità ES6

(sayhello.js):

Object.assign(exports, {
    // Put all your public API here
    sayhello() {
        console.log("Hello World!");
    }
});

(App.js):

const { sayHello } = require('./sayhello');
sayHello(); // "Hello World!"

PS: Sembra che Appcelerator implementa anche i moduli CommonJS, ma senza il supporto di riferimento circolare (vedi: Appcelerator e moduli CommonJS (memorizzazione nella cache e riferimenti circolari) )


35

Alcune cose a cui devi prestare attenzione se assegni un riferimento a un nuovo oggetto a exportse / o modules.exports:

1. Tutte le proprietà / i metodi precedentemente collegati all'originale exportso module.exportsovviamente sono persi perché l'oggetto esportato farà ora riferimento a un altro nuovo

Questo è ovvio, ma se aggiungi un metodo esportato all'inizio di un modulo esistente, assicurati che l'oggetto esportato nativo non faccia riferimento a un altro oggetto alla fine

exports.method1 = function () {}; // exposed to the original exported object
exports.method2 = function () {}; // exposed to the original exported object

module.exports.method3 = function () {}; // exposed with method1 & method2

var otherAPI = {
    // some properties and/or methods
}

exports = otherAPI; // replace the original API (works also with module.exports)

2. Nel caso in cui uno exportso module.exportsfaccia riferimento a un nuovo valore, non fanno più riferimento allo stesso oggetto

exports = function AConstructor() {}; // override the original exported object
exports.method2 = function () {}; // exposed to the new exported object

// method added to the original exports object which not exposed any more
module.exports.method3 = function () {}; 

3. Conseguenza ingannevole. Se cambi il riferimento ad entrambi exportse module.exports, difficile dire quale API sia esposta (sembra module.exportsvittorie)

// override the original exported object
module.exports = function AConstructor() {};

// try to override the original exported object
// but module.exports will be exposed instead
exports = function AnotherConstructor() {}; 

29

la proprietà module.exports o l'oggetto exports consente a un modulo di selezionare ciò che deve essere condiviso con l'applicazione

inserisci qui la descrizione dell'immagine

Ho un video su module_export disponibile qui


18

Quando si divide il codice del programma su più file, module.exportsviene utilizzato per pubblicare variabili e funzioni per l'utente di un modulo. La require()chiamata nel file di origine viene sostituita con il corrispondente module.exportscaricato dal modulo.

Ricorda quando scrivi i moduli

  • I carichi del modulo vengono memorizzati nella cache, solo la chiamata iniziale valuta JavaScript.
  • È possibile utilizzare variabili e funzioni locali all'interno di un modulo, non tutto deve essere esportato.
  • L' module.exportsoggetto è disponibile anche come exportsscorciatoia. Ma quando si restituisce una sola funzione, utilizzare sempre module.exports.

diagramma delle esportazioni del modulo

Secondo: "Moduli Parte 2 - Scrivere moduli" .


9

il link refer è così:

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

le proprietà di exportso module.exports, come funzioni o variabili, saranno esposte all'esterno

c'è qualcosa a cui devi prestare maggiore attenzione: non overrideesportare.

perché ?

poiché esporta solo il riferimento di module.exports, è possibile aggiungere le proprietà alle esportazioni, ma se si sovrascrive le esportazioni, il collegamento di riferimento verrà interrotto.

buon esempio :

exports.name = 'william';

exports.getName = function(){
   console.log(this.name);
}

cattivo esempio:

exports = 'william';

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

Se vuoi solo esporre una sola funzione o variabile, in questo modo:

// test.js
var name = 'william';

module.exports = function(){
    console.log(name);
}   

// index.js
var test = require('./test');
test();

questo modulo ha esposto solo una funzione e la proprietà del nome è privata per l'esterno.


6

Ci sono alcuni moduli predefiniti o esistenti in node.js quando scarichi e installi node.js come http, sys ecc.

Dato che sono già in node.js, quando vogliamo usare questi moduli fondamentalmente ci piacciono i moduli di importazione , ma perché? perché sono già presenti in node.js. L'importazione è come prenderli da node.js e inserirli nel tuo programma. E poi usandoli.

Mentre Exports è esattamente l'opposto, stai creando il modulo che desideri, diciamo il modulo addition.js e inserendo quel modulo in node.js, lo fai esportandolo.

Prima di scrivere qualcosa qui, ricorda, module.exports.additionTwo è lo stesso di exports.additionTwo

Eh, questa è la ragione, ci piace

exports.additionTwo = function(x)
{return x+2;};

Fai attenzione al percorso

Supponiamo che tu abbia creato un modulo addition.js,

exports.additionTwo = function(x){
return x + 2;
};

Quando si esegue questo sul prompt dei comandi NODE.JS:

node
var run = require('addition.js');

Questo sbaglierà dicendo

Errore: impossibile trovare il modulo addition.js

Questo perché il processo node.js non è in grado di add.js poiché non abbiamo menzionato il percorso. Quindi, possiamo impostare il percorso usando NODE_PATH

set NODE_PATH = path/to/your/additon.js

Ora, questo dovrebbe funzionare correttamente senza errori !!

Un'altra cosa, puoi anche eseguire il file addition.js non impostando NODE_PATH, di nuovo al prompt dei comandi di nodejs:

node
var run = require('./addition.js');

Dal momento che stiamo fornendo il percorso qui dicendo che si trova nella directory corrente ./, anche questo dovrebbe funzionare correttamente.


1
è esportazione o esportazione?
rudrasiva86,

Grazie per l'aiuto :)
JumpMan

3

Un modulo incapsula il codice correlato in una singola unità di codice. Quando si crea un modulo, questo può essere interpretato come lo spostamento di tutte le funzioni correlate in un file.

Supponiamo che esista un file Hello.js che include due funzioni

sayHelloInEnglish = function() {
  return "Hello";
};
sayHelloInSpanish = function() {
  return "Hola";
};

Scriviamo una funzione solo quando l'utilità del codice è più di una chiamata.

Supponiamo di voler aumentare l'utilità della funzione in un file diverso, ad esempio World.js, in questo caso l'esportazione di un file viene visualizzata in un'immagine che può essere ottenuta da module.exports.

Puoi semplicemente esportare entrambe le funzioni con il codice indicato di seguito

var anyVariable={
 sayHelloInEnglish = function() {
      return "Hello";
    };
  sayHelloInSpanish = function() {
      return "Hola";
    }; 
}
module.export=anyVariable;

Ora devi solo richiedere il nome del file nell'ordine World.js per usare quelle funzioni

var world= require("./hello.js");

Grazie Se ti ha aiutato, per favore, accetta la mia risposta :)
Shantanu Madane,

1
Un po 'in ritardo
all'amico

@BenTaliadoros anch'io penso che sia in ritardo e penso anche che il suo oggetto anyVariable abbia molti errori. la riga sopra il metodo sayHelloInSpanish non dovrebbe terminare con punto e virgola (;) e la funzione sayHelloInSpanish = è errata. Tutto è sbagliato in questo oggetto. modificherò la sua risposta
divina il

1
la modifica è disabilitata. Cos'altro ha modificato alphadogg in questa risposta ??
divino il

Solo formattazione. A meno che non sia qualcosa di folle es6 che non ho mai incontrato, e sono certo che non lo sia, quindi non è affatto valido JS
Ben Taliadoros

2

L'intento è:

La programmazione modulare è una tecnica di progettazione software che enfatizza la separazione della funzionalità di un programma in moduli indipendenti e intercambiabili, in modo tale che ciascuno contenga tutto il necessario per eseguire solo un aspetto della funzionalità desiderata.

Wikipedia

Immagino che diventi difficile scrivere programmi di grandi dimensioni senza codice modulare / riutilizzabile. In nodejs possiamo creare programmi modulari utilizzando la module.exportsdefinizione di ciò che esponiamo e componiamo il nostro programma require.

Prova questo esempio:

fileLog.js

function log(string) { require('fs').appendFileSync('log.txt',string); }

module.exports = log;

stdoutLog.js

function log(string) { console.log(string); }

module.exports = log;

program.js

const log = require('./stdoutLog.js')

log('hello world!');

eseguire

$ node program.js

Ciao mondo!

Ora prova a scambiare ./stdoutLog.js con ./fileLog.js .


1

Qual è lo scopo di un sistema di moduli?

Compie le seguenti cose:

  1. Mantiene i nostri file dal gonfiore a dimensioni davvero grandi. Avere file con ad es. 5000 righe di codice è solitamente molto difficile da gestire durante lo sviluppo.
  2. Fa rispettare la separazione delle preoccupazioni. La suddivisione del nostro codice in più file ci consente di avere nomi di file appropriati per ogni file. In questo modo possiamo facilmente identificare cosa fa ogni modulo e dove trovarlo (supponendo che abbiamo creato una struttura di directory logica che è ancora una tua responsabilità).

Avere moduli semplifica l'individuazione di alcune parti di codice, il che rende il nostro codice più gestibile.

Come funziona?

NodejS utilizza il sistema di moduli CommomJS che funziona nel modo seguente:

  1. Se un file vuole esportare qualcosa, deve dichiararlo usando la module.exportsintassi
  2. Se un file vuole importare qualcosa, deve dichiararlo usando la require('file')sintassi

Esempio:

test1.js

const test2 = require('./test2');    // returns the module.exports object of a file

test2.Func1(); // logs func1
test2.Func2(); // logs func2

test2.js

module.exports.Func1 = () => {console.log('func1')};

exports.Func2 = () => {console.log('func2')};

Altre cose utili da sapere:

  1. I moduli vengono memorizzati nella cache . Quando si carica lo stesso modulo in 2 file diversi, il modulo deve essere caricato solo una volta. La seconda volta che require()viene chiamato a sullo stesso modulo viene estratto dalla cache.
  2. I moduli sono caricati in sincrono . Questo comportamento è richiesto, se fosse asincrono non potremmo accedere require()immediatamente all'oggetto recuperato .

-3
let test = function() {
    return "Hello world"
};
exports.test = test;

4
Questo è un esempio simile al primo frammento della risposta accettata ( return "Hello world"non fa alcuna differenza), ma senza alcuna spiegazione. Assicurati prima di rispondere che la tua risposta aggiungerà qualcosa all'argomento.
Barbsan,
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.