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

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

根据Node.js文档:

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

但这并没有真正的帮助。

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


当前回答

ECMAScript模块-2022

从Node 14.0开始,ECMAScript模块不再是实验性的,您可以使用它们代替经典Node的CommonJS模块。

ECMAScript模块是打包JavaScript代码以供重用的官方标准格式。模块是使用各种导入和导出语句定义的。

您可以定义导出函数的ES模块:

// my-fun.mjs
function myFun(num) {
  // do something
}

export { myFun };

然后,您可以从my-fun.mjs导入导出的函数:

// app.mjs
import { myFun } from './my-fun.mjs';

myFun();

.mjs是Node.js ECMAScript模块的默认扩展名。但是,在使用package.json“type”字段或CLI中的--input-type标志解析模块时,可以将默认模块扩展配置为查找。

Node.js的最新版本完全支持ECMAScript和CommonJS模块。此外,它还提供了它们之间的互操作性。

模块导出

ECMAScript和CommonJS模块有很多不同之处,但与此问题最相关的区别是,不再需要,不再导出,不再模块。导出

在大多数情况下,ES模块导入可用于加载CommonJS模块。如果需要,可以使用module.createRequire()在ES模块中构造require函数。

ECMAScript模块发布历史记录

Release Changes
v15.3.0, v14.17.0, v12.22.0 Stabilized modules implementation
v14.13.0, v12.20.0 Support for detection of CommonJS named exports
v14.0.0, v13.14.0, v12.20.0 Remove experimental modules warning
v13.2.0, v12.17.0 Loading ECMAScript modules no longer requires a command-line flag
v12.0.0 Add support for ES modules using .js file extension via package.json "type" field
v8.5.0 Added initial ES modules implementation

您可以在Node.js存储库中找到所有变更日志

其他回答

ECMAScript模块-2022

从Node 14.0开始,ECMAScript模块不再是实验性的,您可以使用它们代替经典Node的CommonJS模块。

ECMAScript模块是打包JavaScript代码以供重用的官方标准格式。模块是使用各种导入和导出语句定义的。

您可以定义导出函数的ES模块:

// my-fun.mjs
function myFun(num) {
  // do something
}

export { myFun };

然后,您可以从my-fun.mjs导入导出的函数:

// app.mjs
import { myFun } from './my-fun.mjs';

myFun();

.mjs是Node.js ECMAScript模块的默认扩展名。但是,在使用package.json“type”字段或CLI中的--input-type标志解析模块时,可以将默认模块扩展配置为查找。

Node.js的最新版本完全支持ECMAScript和CommonJS模块。此外,它还提供了它们之间的互操作性。

模块导出

ECMAScript和CommonJS模块有很多不同之处,但与此问题最相关的区别是,不再需要,不再导出,不再模块。导出

在大多数情况下,ES模块导入可用于加载CommonJS模块。如果需要,可以使用module.createRequire()在ES模块中构造require函数。

ECMAScript模块发布历史记录

Release Changes
v15.3.0, v14.17.0, v12.22.0 Stabilized modules implementation
v14.13.0, v12.20.0 Support for detection of CommonJS named exports
v14.0.0, v13.14.0, v12.20.0 Remove experimental modules warning
v13.2.0, v12.17.0 Loading ECMAScript modules no longer requires a command-line flag
v12.0.0 Add support for ES modules using .js file extension via package.json "type" field
v8.5.0 Added initial ES modules implementation

您可以在Node.js存储库中找到所有变更日志

如果将对新对象的引用分配给exports和/或modules.exports,则必须注意以下几点:

1.以前附加到原始导出或模块的所有财产/方法都会丢失。导出当然会丢失,因为导出的对象现在将引用另一个新的对象

这一点很明显,但如果在现有模块的开头添加导出方法,请确保本机导出对象在末尾没有引用另一个对象

exports.method1 = function () {}; // exposed to the original exported object
exports.method2 = function () {}; // exposed to the original exported object

module.exports.method3 = function () {}; // exposed with method1 & method2

var otherAPI = {
    // some properties and/or methods
}

exports = otherAPI; // replace the original API (works also with module.exports)

2.如果exports或module.exports中的一个引用新值,则它们不再引用同一对象

exports = function AConstructor() {}; // override the original exported object
exports.method2 = function () {}; // exposed to the new exported object

// method added to the original exports object which not exposed any more
module.exports.method3 = function () {}; 

3.狡猾的后果。如果同时更改了对exports和module.exports的引用,很难说哪个API是公开的(看起来module.export获胜)

// override the original exported object
module.exports = function AConstructor() {};

// try to override the original exported object
// but module.exports will be exposed instead
exports = function AnotherConstructor() {}; 

目的是:

模块化编程是一种强调将程序的功能分离成独立的,可互换的模块,每个模块都包含所有必要的内容以仅执行期望功能的一个方面。

维基百科

我想,如果没有模块化/可重用代码,编写大型程序会变得困难。在nodejs中,我们可以使用module.exports创建模块化程序,该模块定义了我们公开的内容,并使用require编写程序。

请尝试以下示例:

文件日志.js

function log(string) { require('fs').appendFileSync('log.txt',string); }

module.exports = log;

标准输出日志.js

function log(string) { console.log(string); }

module.exports = log;

程序.js

const log = require('./stdoutLog.js')

log('hello world!');

处决

$node程序.js你好,世界!

现在尝试交换/的stdoutLog.js/fileLog.js。

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

您可以使用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");