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