Node.js - użycie module.exports jako konstruktora

120

Zgodnie z instrukcją Node.js:

Jeśli chcesz, aby korzeniem eksportu modułu była funkcja (taka jak konstruktor) lub jeśli chcesz wyeksportować cały obiekt w jednym przypisaniu, zamiast budować go po jednej właściwości na raz, przypisz go do module.exports zamiast eksportu .

Podany przykład to:

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

i używane w ten sposób:

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

Moje pytanie: dlaczego w przykładzie nie użyto kwadratu jako obiektu? Czy poniższe informacje są poprawne i czy sprawiają, że przykład jest bardziej „zorientowany obiektowo”?

var Square = require('./square.js');
var mySquare = new Square(2);
console.log('The area of my square is ' + mySquare.area());
Naresh
źródło
1
Twój przykład to błąd składni. Po zmianie nazwy squarena już nie istnieje. Squarenew square()
Sukima
3
Przepraszam, to była literówka. Naprawione. Moim zamiarem było pokazanie nazwy obiektu / funkcji zaczynającej się od dużej litery i nazwy instancji zaczynającej się od małej litery.
Naresh
4
Doszedłem do tego, dlatego napisałem odpowiedź tak, jak to zrobiłem. Chciałem tylko powiedzieć, że bardzo się cieszę, że inni patrzą na moduły w ten sam sposób. Często używam słowa kluczowego new i organizuję swoje moduły, aby wyeksportować pojedynczą funkcję konstruktora. Uważam, że ułatwia to czytelność i konceptualizację rozwiązań. Wiem na pierwszy rzut oka, jakiego rodzaju konstrukcji zamierzam użyć. Kudos za myślenie tak jak ja;)
Sukima

Odpowiedzi:

173

Moduły CommonJS pozwalają na dwa sposoby definiowania eksportowanych właściwości. W obu przypadkach zwracasz obiekt / funkcję. Ponieważ funkcje są obywatelami pierwszej klasy w JavaScript, mogą zachowywać się jak obiekty (technicznie rzecz biorąc, są to obiekty). To mówi twoje pytanie dotyczące używanianew słów kluczowych ma prostą odpowiedź: Tak. Zilustruję ...

Eksport modułów

Możesz użyć exportspodanej zmiennej, aby dołączyć do niej właściwości. Gdy będą wymagane w innym module, te przypisane właściwości stają się dostępne. Lub możesz przypisać obiekt do właściwości module.exports. W obu przypadkach to, co jest zwracane przez, require()jest odniesieniem do wartościmodule.exports .

Przykład pseudokodu pokazujący, jak zdefiniowano moduł:

var theModule = {
  exports: {}
};

(function(module, exports, require) {

  // Your module code goes here

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

W powyższym przykładzie module.exportsiexports są tym samym obiektem. Fajne jest to, że nie widzisz nic z tego w swoich modułach CommonJS, ponieważ cały system dba o to za Ciebie.Wszystko, co musisz wiedzieć, jest to, że istnieje obiekt modułu z właściwością eksportu i zmienną eksportu, która wskazuje na to samo robi module.exports.

Wymagaj z konstruktorami

Ponieważ możesz dołączyć funkcję bezpośrednio do module.exports, możesz w zasadzie zwrócić funkcję i jak każda funkcja może być zarządzana jako konstruktor (to jest napisane kursywą, ponieważ jedyną różnicą między funkcją a konstruktorem w JavaScript jest sposób jej użycia. nie ma różnicy.)

A więc poniższy kod jest bardzo dobry i osobiście do tego zachęcam:

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

Wymagaj dla nie-konstruktorów

To samo dotyczy funkcji niebędących konstruktorami:

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

// In another module
var MyModule = require("./my_module.js");
MyModule.someFunction("foobar"); // => "foobar"
Sukima
źródło
2
Czy mogę w skrócie wymagać ('./ my-object.js') ("foobar")? A może składnia require ('module') (params) dla innego przypadku użycia?
Hampus Ahlgren
1
Nic Cię nie powstrzymuje, to tylko JavaScript. Więc tak, możesz użyć krótszej składni.
Sukima
3
Przykład pseudokodu, w jaki sposób definiowany jest moduł, całkowicie wyjaśnił moje zrozumienie systemu modułów Node.js. Dziękuję Ci!
Nitax
130

Moim zdaniem niektóre przykłady node.js są dość wymyślne.

Możesz spodziewać się czegoś podobnego w prawdziwym świecie

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

Stosowanie

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

Dla ludzi z ES6

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

export default Square;

Używanie go w ES6

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

Korzystając z klasy, musisz użyć newsłowa kluczowego, aby ją zainicjować. Wszystko inne pozostaje takie samo.

maček
źródło
3
Niezwykle zwięzła konstrukcja!
Christophe Marois
1
Wygląda więc na to, że w Twoim przykładzie <ES6 nie ma różnicy między jego użyciem newa nieużywaniem. Ale czy to tylko dlatego, że masz ten czek this instanceof square? Jeśli tak, co dokładnie robi ten mechanizm?
arichards
1
Pytania, które miałem i wyszukałem, na wypadek, gdyby było to pomocne dla innych: Gdzie są importi exportzdefiniowane? Są to zastrzeżone słowa kluczowe w ECMAScript 6 (ES6). Przed ES6 trzeba było używać bibliotek do zarządzania modułami. Modulowanie węzła jest wzorowane na modułach biblioteki CommonJS. Co jest defaultw export default Squareśrodku? Określa to, co zaimportować po prostu zaimportować „plik”, a nie inne, konkretne eksporty z tego pliku. Dopóki istnieją, przydały mi się te strony: spring.io/understanding/javascript-modules and exploringjs.com/es6/ch_modules.html
arichards
1

To pytanie tak naprawdę nie ma nic wspólnego z tym, jak require()działa. Zasadniczo wszystko, co ustawisz module.exportsw swoim module, zostanie zwrócone z require()wezwania do tego.

Byłoby to równoważne z:

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

Nie ma potrzeby używania newsłowa kluczowego podczas dzwonienia square. Nie zwracasz samej instancji funkcji z square, na końcu zwracasz nowy obiekt. Dlatego możesz po prostu wywołać tę funkcję bezpośrednio.

Aby newzapoznać się z bardziej zawiłymi argumentami , zobacz: Czy „nowe” słowo kluczowe JavaScript jest uważane za szkodliwe?

Ćwiek
źródło
3
Nie ma nic złego w używaniu nowego słowa kluczowego. Nienawidzę całego FUD wokół tego.
Sukima
1
@Sukima Zgoda. :-D Wskazuję, dlaczego nie ma to znaczenia w tym przypadku i łączy się z innym pytaniem dotyczącym tego, newaby inni mogli tam uczestniczyć w wojnie.
Brad
0

Przykładowy kod to:

w głównej

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

Korzystanie z następujących może działać

exports.square = function(width,callback)
{
     var aa = new Object();
     callback(aa.squareVal = width * width);    
}
AmirtharajCVijay
źródło
0

Na koniec Node dotyczy Javascript. JS ma kilka sposobów, aby coś osiągnąć, otrzymanie „konstruktora” jest tym samym, ważne jest zwrócenie funkcji .

W ten sposób faktycznie tworzysz nową funkcję, tak jak stworzyliśmy na przykład za pomocą JS w środowisku przeglądarki internetowej.

Osobiście wolę podejście prototypowe, jak sugerowała Sukima w tym poście: Node.js - użycie module.exports jako konstruktora

Josue
źródło