Node.js - utilisation de module.exports comme constructeur

120

Selon le manuel Node.js:

Si vous souhaitez que la racine de l'exportation de votre module soit une fonction (comme un constructeur) ou si vous souhaitez exporter un objet complet dans une affectation au lieu de le construire une propriété à la fois, affectez-le à module.exports au lieu d'exporter .

L'exemple donné est:

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

et utilisé comme ceci:

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

Ma question: pourquoi l'exemple n'utilise-t-il pas le carré comme objet? Est-ce que ce qui suit est valide et rend-il l'exemple plus "orienté objet"?

var Square = require('./square.js');
var mySquare = new Square(2);
console.log('The area of my square is ' + mySquare.area());
Naresh
la source
1
Votre exemple est une erreur de syntaxe. Après avoir renommé squareà Squarela new square()plus existe.
Sukima
3
Désolé, c'était une faute de frappe. Corrigé. Mon intention était d'afficher le nom de l'objet / de la fonction en commençant par une majuscule et le nom de l'instance commençant par une minuscule.
Naresh
4
J'ai pensé autant, c'est pourquoi j'ai écrit ma réponse comme je l'ai fait. Je voulais juste dire que je suis vraiment content que les autres regardent les modules de la même manière. J'utilise souvent le nouveau mot-clé et j'organise mes modules pour exporter une seule fonction constructeur. Je trouve que cela facilite la lisibilité et la conceptualisation des solutions. Je peux dire en un coup d'œil quel type de construction je compte utiliser. Félicitations pour avoir pensé comme moi;)
Sukima

Réponses:

173

Les modules CommonJS permettent de définir les propriétés exportées de deux manières. Dans les deux cas, vous renvoyez un objet / une fonction. Parce que les fonctions sont des citoyens de première classe en JavaScript, elles peuvent agir comme des objets (techniquement, ce sont des objets). Cela dit, votre question sur l'utilisation des newmots - clés a une réponse simple: Oui. Je vais illustrer ...

Exportations de modules

Vous pouvez utiliser la exportsvariable fournie pour lui attacher des propriétés. Une fois requis dans un autre module, ces propriétés attribuées deviennent disponibles. Ou vous pouvez affecter un objet à la propriété module.exports. Dans les deux cas, ce qui est renvoyé par require()est une référence à la valeur de module.exports.

Un exemple de pseudo-code de la façon dont un module est défini:

var theModule = {
  exports: {}
};

(function(module, exports, require) {

  // Your module code goes here

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

Dans l'exemple ci module.exports- dessus et exportssont le même objet. La partie intéressante est que vous ne voyez rien de tout cela dans vos modules CommonJS car tout le système s'en charge pour vous.Tout ce que vous devez savoir, c'est qu'il existe un objet module avec une propriété exports et une variable exports qui pointe vers le même chose que module.exports fait.

Exiger avec les constructeurs

Puisque vous pouvez attacher une fonction directement à module.exports vous, vous pouvez essentiellement renvoyer une fonction et comme toute fonction, elle pourrait être gérée en tant que constructeur (c'est en italique puisque la seule différence entre une fonction et un constructeur en JavaScript est la façon dont vous avez l'intention de l'utiliser. Techniquement il n'y a pas de différence.)

Le code suivant est donc parfaitement bon et je l'encourage personnellement:

// 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"

Exiger pour les non-constructeurs

Même chose pour les fonctions comme les non-constructeurs:

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

// In another module
var MyModule = require("./my_module.js");
MyModule.someFunction("foobar"); // => "foobar"
Sukima
la source
2
Puis-je faire require ('./ my-object.js') ("foobar") pour faire court? Ou la syntaxe require ('module') (params) pour un cas d'utilisation différent?
Hampus Ahlgren
1
Rien ne vous arrête, c'est juste du JavaScript. Alors oui, vous pouvez utiliser la syntaxe plus courte.
Sukima
3
L'exemple de pseudo-code de la façon dont un module est défini a complètement éclairci ma compréhension du système de modules Node.js. Je vous remercie!
Nitax
130

À mon avis, certains des exemples de node.js sont assez artificiels.

Vous pourriez vous attendre à voir quelque chose de plus comme ça dans le monde réel

// 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;

Usage

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

Pour les personnes ES6

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

export default Square;

Utilisation dans ES6

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

Lorsque vous utilisez une classe, vous devez utiliser le newmot - clé pour l'instaurer. Tout le reste demeure inchangé.

maček
la source
3
Structure inhabituellement concise!
Christophe Marois
1
Il semble donc que dans votre exemple <ES6, il n'y ait aucune différence entre l'utiliser newet ne pas l'utiliser. Mais est-ce uniquement parce que vous avez ce chèque this instanceof square? Dans l'affirmative, que fait exactement ce mécanisme?
arichards
1
Questions que j'avais et recherchées, au cas où cela serait utile aux autres: où sont importet exportdéfinies? Ce sont des mots clés réservés dans ECMAScript 6 (ES6). Avant ES6, il fallait utiliser des bibliothèques pour gérer les modules. La modulation de Node est calquée sur les modules de la bibliothèque CommonJS. Quel est le defaultdans export default Square? Cela spécifie ce qu'il faut importer lorsque vous importez simplement le «fichier» et pas d'autres exportations spécifiques à partir de ce fichier. Aussi longtemps qu'ils existent, j'ai trouvé ces pages utiles: spring.io/understanding/javascript-modules et exploringjs.com/es6/ch_modules.html
arichards
1

Cette question n'a vraiment rien à voir avec le require()fonctionnement. Fondamentalement, tout ce que vous définissez module.exportsdans votre module sera renvoyé par l' require()appel.

Ce serait équivalent à:

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

Il n'y a pas besoin du newmot - clé lors de l'appel square. Vous ne renvoyez pas l'instance de fonction elle-même square, vous renvoyez un nouvel objet à la fin. Par conséquent, vous pouvez simplement appeler cette fonction directement.

Pour des arguments plus complexes new, consultez ceci: Le «nouveau» mot-clé de JavaScript est-il considéré comme dangereux?

Brad
la source
3
Il n'y a rien de mal à utiliser le nouveau mot-clé. Je déteste tous les FUD qui l'entourent.
Sukima
1
@Sukima D'accord. :-D Je souligne pourquoi cela n'a pas d'importance dans ce cas, et lié à l'autre question concernant newque les autres puissent participer à la guerre là-bas.
Brad
0

L'exemple de code est:

en général

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

l'utilisation de ce qui suit peut fonctionner

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

À la fin, Node parle de Javascript. JS a plusieurs façons d'accomplir quelque chose, c'est la même chose pour obtenir un "constructeur", l'important est de renvoyer une fonction .

De cette façon, en fait, vous créez une nouvelle fonction, comme nous l'avons créée à l'aide de JS sur l'environnement de navigateur Web par exemple.

Personnellement, je préfère l'approche prototype, comme Sukima l'a suggéré sur ce post: Node.js - utilisation de module.exports comme constructeur

Josué
la source