Node.js - использование module.exports как конструктора

Согласно руководству 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

Модули 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, так как вся система заботится о том, что для вас все, что вам нужно знать, - это объект модуля с свойством export и переменной экспорта, которая указывает на то же самое, что и 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

По-моему, некоторые из примеров 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

Этот вопрос не имеет никакого отношения к тому, как работает require(). В принципе, все, что вы установили в своем модуле module.exports, будет возвращено из вызова require() для него.

Это будет эквивалентно:

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

Нет необходимости в ключевом слове new при вызове square. Вы не возвращаете сам экземпляр функции из square, вы возвращаете новый объект в конце. Поэтому вы можете просто вызвать эту функцию напрямую.

Для более сложных аргументов вокруг new, проверьте это: Является ли JavaScript 'new " ключевое слово считается вредным?

Ответ 4

Пример кода:

в главном

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

используя следующие действия:

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

Ответ 5

В конце, Node о Javascript. У JS есть несколько способов сделать что-то, это то же самое, что получить "конструктор", важно вернуть функцию.

Таким образом, на самом деле вы создаете новую функцию, как, например, мы создали с помощью JS в среде веб-браузера.

Лично я предпочитаю подход прототипа, как Sukima предложил на этом посте: Node.js - использование module.exports в качестве конструктора

Ответ 6

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