Node.js module.exports的用途是什么?您如何使用它?

我似乎找不到关于这个的任何信息,但它似乎是Node.js的一个相当重要的部分,因为我经常在源代码中看到它。

根据Node.js文档:

单元参考电流单元特别是module.exports与导出对象相同。看见src/node.js获取更多信息。

但这并没有真正的帮助。

module.exports到底做什么?一个简单的例子是什么?


当前回答

将程序代码划分为多个文件时,module.exports用于向模块的使用者发布变量和函数。源文件中的require()调用将替换为从模块加载的相应module.exports。

编写模块时记住

模块加载被缓存,只有初始调用评估JavaScript。可以在模块中使用局部变量和函数,而不需要导出所有内容。module.exports对象也可用作导出速记。但当返回一个单独的函数时,请始终使用module.exports。

根据:“模块第2部分-编写模块”。

其他回答

请注意,NodeJS模块机制基于CommonJS模块,这些模块在许多其他实现中都受支持,如RequireJS,但也包括SproutCore、CouchDB、Wakanda、OrientDB、ArangoDB、RingoJS、TeaJS、SilkJS、curl.js,甚至Adobe Photoshop(通过PSLib)。您可以在这里找到已知实现的完整列表。

除非您的模块使用特定于节点的特性或模块,否则我强烈建议您使用导出,而不是不属于CommonJS标准的module.exports,并且其他实现通常不支持。

另一个特定于NodeJS的特性是,当您将一个引用分配给一个要导出的新对象时,而不是像Jed Watson在这个线程中提供的最后一个示例那样向其添加财产和方法。我个人不赞成这种做法,因为这打破了CommonJS模块机制的循环引用支持。它不是所有实现都支持的,Jed示例应该以这种方式(或类似的方式)编写,以提供更通用的模块:

(sayhello.js):

exports.run = function() {
    console.log("Hello World!");
}

(app.js):

var sayHello = require('./sayhello');
sayHello.run(); // "Hello World!"

或使用ES6功能

(sayhello.js):

Object.assign(exports, {
    // Put all your public API here
    sayhello() {
        console.log("Hello World!");
    }
});

(app.js):

const { sayHello } = require('./sayhello');
sayHello(); // "Hello World!"

PS:看起来Appcelerator也实现了CommonJS模块,但没有循环引用支持(参见:Appcelerater和CommonJS模块(缓存和循环引用))

将程序代码划分为多个文件时,module.exports用于向模块的使用者发布变量和函数。源文件中的require()调用将替换为从模块加载的相应module.exports。

编写模块时记住

模块加载被缓存,只有初始调用评估JavaScript。可以在模块中使用局部变量和函数,而不需要导出所有内容。module.exports对象也可用作导出速记。但当返回一个单独的函数时,请始终使用module.exports。

根据:“模块第2部分-编写模块”。

这已经得到了回答,但我想补充一些澄清。。。

您可以使用exports和module.exports将代码导入应用程序,如下所示:

var mycode=require('./path/to/mycode');

您将看到的基本用例(例如在ExpressJS示例代码中)是在.js文件中的exports对象上设置财产,然后使用require()导入该文件

因此,在一个简单的计数示例中,您可以:

(counter.js):

var count = 1;

exports.increment = function() {
    count++;
};

exports.getCount = function() {
    return count;
};

…然后在您的应用程序(web.js或任何其他.js文件)中:

var counting = require('./counter.js');

console.log(counting.getCount()); // 1
counting.increment();
console.log(counting.getCount()); // 2

简单地说,您可以将所需文件视为返回单个对象的函数,并且可以通过在导出时设置它们,将财产(字符串、数字、数组、函数等)添加到返回的对象中。

有时您会希望require()调用返回的对象是可以调用的函数,而不仅仅是具有财产的对象。在这种情况下,还需要设置module.exports,如下所示:

(sayhello.js):

module.exports = exports = function() {
    console.log("Hello World!");
};

(app.js):

var sayHello = require('./sayhello.js');
sayHello(); // "Hello World!"

这里的答案更好地解释了exports和module.exports之间的区别。

模块将相关代码封装为单个代码单元。创建模块时,这可以解释为将所有相关函数移动到文件中。

假设有一个文件Hello.js,其中包含两个函数

sayHelloInEnglish = function() {
  return "Hello";
};
sayHelloInSpanish = function() {
  return "Hola";
};

只有当代码的实用程序不止一次调用时,我们才编写函数。

假设我们想将函数的实用性增加到另一个文件,比如World.js,在这种情况下,导出一个文件会变成图片,可以通过module.exports获得。

您可以通过下面给出的代码同时导出这两个函数

var anyVariable={
 sayHelloInEnglish = function() {
      return "Hello";
    };
  sayHelloInSpanish = function() {
      return "Hola";
    }; 
}
module.export=anyVariable;

现在您只需要将文件名输入World.js即可使用这些函数

var world= require("./hello.js");

module.exports是作为require调用的结果实际返回的对象。

exports变量最初被设置为同一个对象(即,它是一个简写“别名”),因此在模块代码中,您通常会编写如下内容:

let myFunc1 = function() { ... };
let myFunc2 = function() { ... };
exports.myFunc1 = myFunc1;
exports.myFunc2 = myFunc2;

导出(或“公开”)内部作用域函数myFunc1和myFunc2。

在调用代码中,您将使用:

const m = require('./mymodule');
m.myFunc1();

其中最后一行显示require的结果(通常)只是一个可以访问其财产的普通对象。

注意:如果您覆盖导出,则它将不再引用module.exports。因此,如果您希望为导出分配新对象(或函数引用),则还应将该新对象分配给module.export


值得注意的是,添加到导出对象的名称不必与要添加的值的模块内部作用域名称相同,因此可以:

let myVeryLongInternalName = function() { ... };
exports.shortName = myVeryLongInternalName;
// add other objects, functions, as required

然后:

const m = require('./mymodule');
m.shortName(); // invokes module.myVeryLongInternalName