Node.js - 使用 module.exports 作为构造函数

IT技术 javascript node.js commonjs
2021-03-08 10:52:54

根据 Node.js 手册:

如果您希望module导出的根是一个函数(例如构造函数),或者如果您想在一次分配中导出一个完整的对象而不是一次构建一个属性,请将其分配给 module.exports 而不是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());

我的问题:为什么这个例子不使用 square 作为对象?以下内容是否有效,是否使示例更加“面向对象”?

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

CommonJS module允许通过两种方式定义导出的属性。无论哪种情况,您都将返回一个对象/函数。因为函数是 JavaScript 中的一等公民,所以它们可以像对象一样运行(从技术上讲,它们是对象)。也就是说,您关于使用new关键字的问题有一个简单的答案:是的。我来说明...

module导出

您可以使用exports提供变量将属性附加到它。一旦在另一个module中需要这些分配属性就变得可用。或者您可以将一个对象分配给 module.exports 属性。在任何一种情况下,返回的require()都是对 的值的引用module.exports

如何定义module的伪代码示例:

var theModule = {
  exports: {}
};

(function(module, exports, require) {

  // Your module code goes here

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

在上面的例子中module.exportsexports是同一个对象。很酷的部分是,您在 CommonJS module中看不到任何内容,因为整个系统会为您处理这些问题,您只需要知道有一个带有导出属性的module对象和一个指向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"
module定义的伪代码示例,彻底澄清了我对 Node.js module系统的理解。谢谢!
2021-05-01 10:52:54
我可以简写为 require('./my-object.js')("foobar") 吗?或者 require('module')(params) 语法是否适用于不同的用例?
2021-05-08 10:52:54
没有什么能阻止你,这只是 JavaScript。所以是的,您可以使用较短的语法。
2021-05-16 10:52:54

在我看来,一些 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关键字来实例化它。其他一切都保持不变。

结构异常简洁!
2021-04-22 10:52:54
我遇到并查找的问题,以防对其他人有帮助:在哪里importexport定义?这些是 ECMAScript 6 (ES6) 中的保留关键字。在 ES6 之前,必须使用库来管理module。Node 的module化模仿了 CommonJS 库的module。什么是defaultexport default Square这指定了当您只导入“文件”而不是该文件的其他特定导出时要导入的内容。只要它们存在,我就发现这些页面很有帮助:spring.io/understanding/javascript-modulesexplorejs.com/es6/ch_modules.html
2021-04-30 10:52:54
因此,在您的 <ES6 示例中,使用new和不使用它似乎没有区别但是,这仅仅是因为您有支票this instanceof square吗?如果是这样,该机制究竟在做什么?
2021-05-17 10:52:54

这个问题与require()工作原理没有任何关系基本上,您module.exports在module中设置的任何内容都将从require()调用中返回

这相当于:

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

new调用时不需要关键字square您不是从 返回函数实例本身square,而是在最后返回一个新对象。因此,您可以直接调用此函数。

有关更复杂的参数new,请查看: JavaScript 的“new”关键字是否被认为有害?

使用 new 关键字没有任何问题。我讨厌它周围的所有 FUD。
2021-04-24 10:52:54
@Sukima 同意。:-D 我指出为什么在这种情况下无关紧要,并与另一个问题相关联,new以便其他人可以在那里参与战争。
2021-05-08 10:52:54

示例代码是:

在主要

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

使用以下可能有效

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

最后,Node 是关于 Javascript 的。JS 有几种方法来完成某事,获取“构造函数”是同一件事,重要的是返回一个函数

这样实际上您正在创建一个新函数,例如我们在 Web 浏览器环境中使用 JS 创建的。

我个人更喜欢原型方法,正如 Sukima 在这篇文章中所建议的:Node.js - use of module.exports as a constructor