Node.js - Verwendung von module.exports als Konstruktor

120

Laut dem Node.js-Handbuch:

Wenn Sie möchten, dass das Stammverzeichnis des Exports Ihres Moduls eine Funktion ist (z. B. ein Konstruktor), oder wenn Sie ein vollständiges Objekt in einer Zuweisung exportieren möchten, anstatt jeweils eine Eigenschaft zu erstellen, weisen Sie es module.exports anstelle von export zu .

Das gegebene Beispiel ist:

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

und so verwendet:

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

Meine Frage: Warum verwendet das Beispiel kein Quadrat als Objekt? Ist das Folgende gültig und macht es das Beispiel "objektorientierter"?

var Square = require('./square.js');
var mySquare = new Square(2);
console.log('The area of my square is ' + mySquare.area());
Naresh
quelle
1
Ihr Beispiel ist ein Syntaxfehler. Nach dem Umbenennen squarein existiert Squaredas new square()nicht mehr.
Sukima
3
Entschuldigung, das war ein Tippfehler. Behoben. Meine Absicht war es, den Objekt- / Funktionsnamen beginnend mit Großbuchstaben und den Instanznamen beginnend mit Kleinbuchstaben anzuzeigen.
Naresh
4
Ich dachte mir das auch. Deshalb habe ich meine Antwort so geschrieben, wie ich es getan habe. Ich wollte nur sagen, dass ich wirklich froh bin, dass andere Module auf die gleiche Weise betrachten. Ich verwende oft das neue Schlüsselwort und organisiere meine Module, um eine einzelne Konstruktorfunktion zu exportieren. Ich finde, es erleichtert die Lesbarkeit und Konzeptualisierung von Lösungen. Ich kann auf einen Blick erkennen, welche Art von Konstrukt ich verwenden möchte. Ein
großes Lob

Antworten:

173

Mit CommonJS-Modulen können exportierte Eigenschaften auf zwei Arten definiert werden. In beiden Fällen geben Sie ein Objekt / eine Funktion zurück. Da Funktionen in JavaScript erstklassige Bürger sind, können sie sich wie Objekte verhalten (technisch gesehen sind sie Objekte). Ihre Frage zur Verwendung der newSchlüsselwörter hat jedoch eine einfache Antwort: Ja. Ich werde veranschaulichen ...

Modulexporte

Sie können entweder die exportsbereitgestellte Variable verwenden, um Eigenschaften daran anzuhängen. Sobald diese Zuweisungseigenschaften in einem anderen Modul erforderlich sind, werden sie verfügbar. Oder Sie können der Eigenschaft module.exports ein Objekt zuweisen. In beiden Fällen require()wird ein Verweis auf den Wert von zurückgegeben module.exports.

Ein Pseudocode-Beispiel für die Definition eines Moduls:

var theModule = {
  exports: {}
};

(function(module, exports, require) {

  // Your module code goes here

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

Im obigen Beispiel module.exportsund exportssind das gleiche Objekt. Der coole Teil ist, dass Sie nichts davon in Ihren CommonJS-Modulen sehen, da das gesamte System sich darum kümmert. Alles, was Sie wissen müssen, ist, dass es ein Modulobjekt mit einer Exporteigenschaft und einer Exportvariablen gibt, die auf das zeigt das gleiche macht das module.exports.

Mit Konstruktoren anfordern

Da Sie eine Funktion direkt anhängen können, können module.exportsSie im Wesentlichen eine Funktion zurückgeben und wie jede Funktion als Konstruktor verwalten. (Dies ist kursiv dargestellt, da der einzige Unterschied zwischen einer Funktion und einem Konstruktor in JavaScript darin besteht, wie Sie sie verwenden möchten. Technisch es gibt keinen Unterschied.)

Folgendes ist also ein perfekter Code, und ich persönlich ermutige ihn:

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

Für Nichtkonstruktoren erforderlich

Gleiches gilt für nicht konstruktorähnliche Funktionen:

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

// In another module
var MyModule = require("./my_module.js");
MyModule.someFunction("foobar"); // => "foobar"
Sukima
quelle
2
Kann ich kurz ('./ my-object.js') ("foobar") benötigen? Oder ist die Syntax require ('module') (params) für einen anderen Anwendungsfall?
Hampus Ahlgren
1
Nichts hält dich davon ab, es ist alles nur JavaScript. Also ja, Sie können die kürzere Syntax verwenden.
Sukima
3
Das Pseudocode-Beispiel für die Definition eines Moduls hat mein Verständnis des Node.js-Modulsystems vollständig geklärt. Danke dir!
Nitax
130

Meiner Meinung nach sind einige der Beispiele von node.j ziemlich erfunden.

Sie könnten erwarten, so etwas in der realen Welt zu sehen

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

Verwendung

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

Für die ES6-Leute

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

export default Square;

Verwenden Sie es in ES6

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

Wenn Sie eine Klasse verwenden, müssen Sie das newSchlüsselwort verwenden, um sie zu instanziieren. Alles andere bleibt gleich.

maček
quelle
3
Ungewöhnlich prägnante Struktur!
Christophe Marois
1
In Ihrem <ES6-Beispiel scheint es also keinen Unterschied zu geben, ob Sie es verwenden newoder nicht. Aber ist das nur so, weil Sie diesen Scheck haben this instanceof square? Wenn ja, was genau macht dieser Mechanismus?
Arichards
1
Fragen, die ich hatte und nachgeschlagen habe, falls es für andere hilfreich ist: Wo sind importund exportdefiniert? Dies sind reservierte Schlüsselwörter in ECMAScript 6 (ES6). Vor ES6 musste man Bibliotheken verwenden, um Module zu verwalten. Die Modulation des Knotens ist den Modulen der CommonJS-Bibliothek nachempfunden. Was ist das defaultin export default Square? Dies gibt an, was importiert werden soll, wenn Sie nur die 'Datei' importieren und nicht andere, spezifische Exporte aus dieser Datei. Solange sie existieren, fand ich diese Seiten hilfreich: spring.io/understanding/javascript-modules und exploringjs.com/es6/ch_modules.html
arichards
1

Diese Frage hat eigentlich nichts damit zu tun, wie es require()funktioniert. Grundsätzlich wird alles, was Sie module.exportsin Ihrem Modul eingestellt haben, vom require()Aufruf zurückgesendet.

Dies wäre gleichbedeutend mit:

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

newBeim Aufrufen ist das Schlüsselwort nicht erforderlich square. Sie geben nicht die Funktionsinstanz selbst zurück square, sondern am Ende ein neues Objekt. Daher können Sie diese Funktion einfach direkt aufrufen.

Weitere Informationen zu komplizierten Argumenten newfinden Sie hier: Wird das "neue" Schlüsselwort von JavaScript als schädlich eingestuft?

Brad
quelle
3
Es ist nichts Falsches daran, das neue Schlüsselwort zu verwenden. Ich hasse die ganze FUD darum herum.
Sukima
1
@ Sukima vereinbart. :-D Ich weise darauf hin, warum es in diesem Fall nicht wichtig ist, und bin mit der anderen Frage verbunden, newdamit andere dort am Krieg gegen sie teilnehmen können.
Brad
0

Der Beispielcode lautet:

in der Hauptsache

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

Die Verwendung der folgenden kann funktionieren

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

Am Ende geht es bei Node um Javascript. JS hat mehrere Möglichkeiten, etwas zu erreichen. Es ist dasselbe, einen "Konstruktor" zu erhalten. Wichtig ist, eine Funktion zurückzugeben .

Auf diese Weise erstellen Sie tatsächlich eine neue Funktion, wie wir sie beispielsweise mit JS in einer Webbrowser-Umgebung erstellt haben.

Persönlich bevorzuge ich den Prototyp-Ansatz, wie Sukima in diesem Beitrag vorgeschlagen hat: Node.js - Verwendung von module.exports als Konstruktor

Josue
quelle