Node.js - використання module.exports як конструктора


120

Відповідно до посібника Node.js:

Якщо ви хочете, щоб корень експорту вашого модуля був функцією (наприклад, конструктором) або якщо ви хочете експортувати повний об'єкт в одному призначенні, а не будувати його по одному властивості за один раз, призначте його module.exports замість експорту .

Наведений приклад:

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

і використовується так:

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

Моє запитання: чому приклад не використовує квадрат як об’єкт? Чи дійсне наступне та чи робить приклад більш "орієнтованим на об'єкти"?

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

1
Ваш приклад - синтаксична помилка. Після перейменування не squareв більше не існує. Squarenew square()
Сукіма

3
Вибачте, це була помилка. Виправлено це. Я мав намір показати ім'я об’єкта / функції, починаючи з верхнього регістру та імені екземпляра, починаючи з нижнього регістру.
Нареш

4
Я подумав стільки, тому я написав свою відповідь так, як і зробив. Я просто хотів сказати, що дуже радий, що інші дивляться на модулі так само. Я часто використовую нове ключове слово та організовую свої модулі для експорту однієї функції конструктора. Я вважаю, що це полегшує читабельність та концептуалізацію рішень. Я можу з першого погляду сказати, яку конструкцію я маю намір використати. Kudos для того, щоб думати, як я;)
Sukima

Відповіді:


173

Модулі CommonJS дозволяють два способи визначення експортованих властивостей. В будь-якому випадку ви повертаєте об'єкт / функцію. Оскільки функції є першокласними громадянами в JavaScript, вони можуть діяти так само, як Об'єкти (технічно це Об'єкти). На це запитання щодо використання newключових слів є проста відповідь: так. Я проілюструю ...

Експорт модуля

Ви можете використовувати exportsзмінну, надану для додавання до неї властивостей. Після необхідності в іншому модулі ці властивості призначення присвоюються. Або ви можете призначити об'єкт властивості module.exports. В будь-якому випадку те, що повертається, require()- це посилання на значення module.exports.

Приклад псевдокоду, як визначається модуль:

var theModule = {
  exports: {}
};

(function(module, exports, require) {

  // Your module code goes here

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

У наведеному вище прикладі є одним module.exportsі exportsтим же об'єктом. Класна частина полягає в тому, що ви не бачите нічого з цього у своїх модулях CommonJS, оскільки вся система піклується про те, що для вас все, що вам потрібно знати, є об’єкт модуля з властивістю експорту та змінною експорту, яка вказує на те саме, що робить module.exports.

Вимагайте з конструкторами

Оскільки ви можете приєднати функцію безпосередньо до module.exportsвас, ви можете по суті повернути функцію, як і будь-якою функцією, нею можна керувати як конструктор (Це курсивом, оскільки єдина різниця між функцією та конструктором у JavaScript - це те, як ви маєте намір її використовувати. Технічно різниці немає.)

Отже, наступний ідеально хороший код, і я особисто його заохочую:

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

Вимога для неконструкторів

Те ж саме стосується і неконструкторських функцій:

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

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

2
Чи можу я вимагати ('./ my-object.js') ("foobar") коротко? Або синтаксис вимагає ('module') (params) для іншого випадку використання?
Hampus Ahlgren

1
Ніщо не зупиняє вас, це все лише JavaScript. Так що так, ви можете використовувати коротший синтаксис.
Сукіма

3
Приклад псевдокоду того, як визначений модуль, повністю прояснив моє розуміння модульної системи Node.js. Дякую!
Nitax

130

На мою думку, деякі приклади node.js досить надумані.

Ви можете розраховувати побачити щось подібне в реальному світі

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

Використання

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

Для людей ES6

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

export default Square;

Використовуючи його в ES6

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

Під час використання класу ви повинні використовувати newключове слово, щоб встановити його. Все інше залишається таким же.


3
Незвично лаконічна структура!
Крістоф Маруа

1
Отже, схоже, що у вашому <ES6-прикладі немає різниці між використанням newта нею. Але це лише тому, що ви маєте на це чек this instanceof square? Якщо так, то що саме робить цей механізм?
arichards

1
Питання, які я мав і шукав, якщо це корисно для інших: Де importі де exportвизначені? Це зарезервовані ключові слова в ECMAScript 6 (ES6). До ES6 потрібно було використовувати бібліотеки для управління модулями. Модулювання вузла моделюється після модулів бібліотеки CommonJS. Що таке defaultв export default Square? Це визначає, що потрібно імпортувати, коли ви просто імпортуєте "файл", а не інший конкретний експорт із цього файлу. Для тих пір , поки вони існують, я знайшов ці сторінки корисний: spring.io/understanding/javascript-modules і exploringjs.com/es6/ch_modules.html
arichards

1

Це питання насправді не має нічого спільного з тим, як require()працює. По суті, все, що ви встановите module.exportsу своєму модулі, буде повернуто з require()виклику.

Це було б рівнозначно:

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

Під newчас виклику ключового слова немає необхідності square. Ви не повертаєте сам екземпляр функції square, ви повертаєте новий об'єкт в кінці. Тому ви можете просто викликати цю функцію безпосередньо.

Щоб отримати більш складні аргументи new, перевірте це: чи вважається "новим" ключове слово JavaScript шкідливим?


3
Немає нічого поганого у використанні нового ключового слова. Я ненавиджу весь FUD навколо нього.
Сукіма

1
@Sukima погодився. :-D Я вказую, чому це не має значення в даному випадку, і пов'язаний з іншим питанням щодо того, newщоб інші могли брати участь у війні там.
Бред

0

Приклад коду:

в основному

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

використання наступного може працювати

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

0

Зрештою, Node про Javascript. У JS є кілька способів чогось здійснити, це одне і те ж, щоб отримати «конструктора», важливо - повернути функцію .

Таким чином, ви фактично створюєте нову функцію, як ми створили, наприклад, за допомогою JS у середовищі веб-браузера.

Особисто я віддаю перевагу прототиповому підходу, як Сукіма запропонував у цій публікації: Node.js - використання module.exports як конструктора

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.