Node.js: utilizzo di module.exports come costruttore


120

Secondo il manuale di Node.js:

Se vuoi che la radice dell'esportazione del tuo modulo sia una funzione (come un costruttore) o se vuoi esportare un oggetto completo in un'assegnazione invece di costruirlo una proprietà alla volta, assegnalo a module.exports invece che alle esportazioni .

L'esempio fornito è:

// file: square.js
module.exports = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}

e usato in questo modo:

var square = require('./square.js');
var mySquare = square(2);
console.log('The area of my square is ' + mySquare.area());

La mia domanda: perché l'esempio non usa il quadrato come oggetto? Quanto segue è valido e rende l'esempio più "orientato agli oggetti"?

var Square = require('./square.js');
var mySquare = new Square(2);
console.log('The area of my square is ' + mySquare.area());

1
Il tuo esempio è un errore di sintassi. Dopo aver rinominato squareper Squarela new square()non esiste più.
Sukima

3
Scusa, è stato un errore di battitura. Aggiustato. La mia intenzione era di mostrare il nome dell'oggetto / funzione che inizia con le lettere maiuscole e il nome dell'istanza che inizia con le lettere minuscole.
Naresh

4
Ho pensato altrettanto, ecco perché ho scritto la mia risposta nel modo in cui l'ho fatto. Volevo solo dire che sono davvero contento che gli altri guardino i moduli allo stesso modo. Uso spesso la nuova parola chiave e organizzo i miei moduli per esportare una singola funzione di costruzione. Trovo che renda più facile la leggibilità e la concettualizzazione delle soluzioni. Posso dire a colpo d'occhio che tipo di costrutto intendo utilizzare. Complimenti per aver pensato come me;)
Sukima

Risposte:


173

I moduli CommonJS consentono due modi per definire le proprietà esportate. In entrambi i casi stai restituendo un oggetto / funzione. Poiché le funzioni sono cittadini di prima classe in JavaScript, possono agire proprio come oggetti (tecnicamente sono oggetti). Detto questo, la tua domanda sull'utilizzo delle newparole chiave ha una risposta semplice: sì. Illustrerò ...

Esporta il modulo

È possibile utilizzare la exportsvariabile fornita per associarvi le proprietà. Una volta richieste in un altro modulo, quelle proprietà assegnate diventano disponibili. Oppure puoi assegnare un oggetto alla proprietà module.exports. In entrambi i casi ciò che viene restituito da require()è un riferimento al valore di module.exports.

Un esempio di pseudo-codice di come viene definito un modulo:

var theModule = {
  exports: {}
};

(function(module, exports, require) {

  // Your module code goes here

})(theModule, theModule.exports, theRequireFunction);

Nell'esempio sopra module.exportse exportssono lo stesso oggetto. La parte interessante è che non vedi nulla di tutto ciò nei tuoi moduli CommonJS poiché l'intero sistema si prende cura di questo per te tutto ciò che devi sapere è che c'è un oggetto modulo con una proprietà di esportazione e una variabile di esportazione che punta al stessa cosa fa il module.exports.

Richiedi con i costruttori

Dal momento che puoi allegare una funzione direttamente a module.exports, puoi essenzialmente restituire una funzione e come qualsiasi funzione potrebbe essere gestita come un costruttore (è in corsivo poiché l'unica differenza tra una funzione e un costruttore in JavaScript è come intendi usarlo. non c'è differenza.)

Quindi il seguente è un codice perfettamente valido e personalmente lo incoraggio:

// My module
function MyObject(bar) {
  this.bar = bar;
}

MyObject.prototype.foo = function foo() {
  console.log(this.bar);
};

module.exports = MyObject;

// In another module:
var MyObjectOrSomeCleverName = require("./my_object.js");
var my_obj_instance = new MyObjectOrSomeCleverName("foobar");
my_obj_instance.foo(); // => "foobar"

Richiedi per i non costruttori

La stessa cosa vale per le funzioni non di tipo costruttore:

// My Module
exports.someFunction = function someFunction(msg) {
  console.log(msg);
}

// In another module
var MyModule = require("./my_module.js");
MyModule.someFunction("foobar"); // => "foobar"

2
Posso richiedere ('./ my-object.js') ("foobar") in breve? Oppure la sintassi require ('module') (params) per un caso d'uso diverso?
Hampus Ahlgren

1
Niente ti ferma, è tutto solo JavaScript. Quindi sì, puoi usare la sintassi più breve.
Sukima

3
L'esempio di pseudo-codice di come viene definito un modulo ha completamente chiarito la mia comprensione del sistema di moduli Node.js. Grazie!
Nitax

130

A mio parere, alcuni esempi di node.js sono abbastanza artificiosi.

Potresti aspettarti di vedere qualcosa di più simile a questo nel mondo reale

// square.js
function Square(width) {

  if (!(this instanceof Square)) {
    return new Square(width);
  }

  this.width = width;
};

Square.prototype.area = function area() {
  return Math.pow(this.width, 2);
};

module.exports = Square;

uso

var Square = require("./square");

// you can use `new` keyword
var s = new Square(5);
s.area(); // 25

// or you can skip it!
var s2 = Square(10);
s2.area(); // 100

Per le persone ES6

class Square {
  constructor(width) {
    this.width = width;
  }
  area() {
    return Math.pow(this.width, 2);
  }
}

export default Square;

Usandolo in ES6

import Square from "./square";
// ...

Quando si utilizza una classe, è necessario utilizzare la newparola chiave per istanziarla. Tutto il resto rimane lo stesso.


3
Struttura insolitamente concisa!
Christophe Marois

1
Quindi sembra che nel tuo esempio <ES6 non ci sia differenza tra usarlo newe non usarlo. Ma è solo perché hai quell'assegno this instanceof square? In tal caso, cosa sta facendo esattamente quel meccanismo?
arichards

1
Domande che avevo e ho cercato, nel caso in cui sia utile per gli altri: dove sono importe exportdefiniti? Queste sono parole chiave riservate in ECMAScript 6 (ES6). Prima di ES6, era necessario utilizzare le librerie per gestire i moduli. La modulazione di Node è modellata sui moduli della libreria CommonJS. Cosa c'è defaultdentro export default Square? Specifica cosa importare quando si importa solo il "file" e non altre esportazioni specifiche da quel file. Per tutto il tempo come esistono, ho trovato queste pagine utili: spring.io/understanding/javascript-modules e exploringjs.com/es6/ch_modules.html
arichards

1

Questa domanda non ha davvero nulla a che fare con come require()funziona. Fondamentalmente, qualunque cosa tu abbia impostato module.exportsnel tuo modulo verrà restituito dalla require()chiamata.

Questo sarebbe equivalente a:

var square = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}

Non è necessaria la newparola chiave durante la chiamata square. Non stai restituendo l'istanza della funzione stessa square, stai restituendo un nuovo oggetto alla fine. Pertanto, puoi semplicemente chiamare direttamente questa funzione.

Per argomenti più complessi in giro new, controlla questo: la "nuova" parola chiave di JavaScript è considerata dannosa?


3
Non c'è niente di sbagliato nell'usare la nuova parola chiave. Odio tutto il FUD intorno ad esso.
Sukima

1
@Sukima d'accordo. MrGreen Sto precisando perché non importa in questo caso, e legato all'altra domanda riguardante newcosì che altri possano partecipare alla guerra su di essa lì.
Brad

0

Il codice di esempio è:

in principale

square(width,function (data)
{
   console.log(data.squareVal);
});

utilizzando quanto segue può funzionare

exports.square = function(width,callback)
{
     var aa = new Object();
     callback(aa.squareVal = width * width);    
}

0

Alla fine, Node riguarda Javascript. JS ha diversi modi per realizzare qualcosa, è la stessa cosa per ottenere un "costruttore", l'importante è restituire una funzione .

In questo modo in realtà stai creando una nuova funzione, come abbiamo creato utilizzando JS su ambiente Web Browser, ad esempio.

Personalmente preferisco l'approccio prototipo, come suggerito da Sukima in questo post: Node.js - uso di module.exports come costruttore

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.