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

时间:2013-12-12 03:53:14

标签: javascript node.js commonjs

根据Node.js手册:

  

如果您希望模块导出的根是一个函数(例如   构造函数)或者如果要在一个中导出完整的对象   分配而不是一次构建一个属性,将其分配给   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 个答案:

答案 0 :(得分:162)

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.exportsexports是同一个对象。很酷的部分是你在CommonJS模块中看不到任何这些,因为整个系统都会为你解决这个问题,你需要知道的是有一个带有exports属性的模块对象和一个指向与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"

答案 1 :(得分:124)

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

答案 2 :(得分:1)

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

这相当于:

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

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

对于围绕new的更复杂的参数,请查看:Is JavaScript's "new" keyword considered harmful?

答案 3 :(得分:0)

示例代码为:

中的

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

使用以下内容可能有效

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

答案 4 :(得分:0)

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

实际上,您是通过这种方式创建新功能的,例如我们在Web浏览器环境中使用JS创建的功能。

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