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

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

我似乎找不到任何相关信息,但它似乎是 Node.js 的重要组成部分,正如我在源代码中经常看到的那样。

根据Node.js 文档

模组

对当前module引用。特别是module.exports与导出对象相同。有关更多信息,请参见src/node.js

但这并没有真正的帮助。

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

答案

module.exports是由于require调用而实际返回的对象。

最初, exports变量设置为相同的对象(即,它是 “alias” 的简写),因此在模块代码中,您通常会编写如下代码:

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

导出(或 “暴露”)内部作用域函数myFunc1myFunc2

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

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

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

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


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

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

其次是:

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

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

您可以使用这两个exportsmodule.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

简而言之,您可以将所需的文件视为返回单个对象的函数,并且可以通过在exports上设置它们来为返回的对象添加属性(字符串,数字,数组,函数,任何东西)。

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

(sayhello.js):

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

(app.js):

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

此答案中,可以更好地解释 export 和 module.exports 之间的区别。

请注意,NodeJS 模块机制基于CommonJS模块,该模块在RequireJS等许多其他实现中也受支持,还包括SproutCoreCouchDBWakandaOrientDBArangoDBRingoJSTeaJSSilkJScurl.js甚至Adobe Photoshop (通过PSLib) )。您可以在此处找到已知实现的完整列表。

除非你的模块使用节点特定功能或模块,我强烈建议您使用再exports ,而不是module.exports 这不是 CommonJS 的标准的一部分 ,然后大多没有其他实现的支持。

NodeJS 的另一项特定功能是,当您分配对要exports的新对象的引用时,不像 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 模块,但是没有循环引用支持(请参阅: Appcelerator 和 CommonJS 模块(缓存和循环引用)

有的几件事情,如果你分配给新的对象的引用你必须要小心exports和 / 或modules.exports

1. 先前附加到原始exportsmodule.exports所有属性 / 方法都将丢失,因为导出的对象现在将引用另一个新对象

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

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. 如果exportsmodule.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. 棘手的结果。如果更改,参照上述两个exportsmodule.exports ,很难说哪个 API 暴露(它看起来像module.exports胜)

// 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() {};

module.exports 属性或 exports 对象允许模块选择应与应用程序共享的内容

在此处输入图片说明

我在此处有关于 module_export 的视频

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

在编写模块时记住

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

模块出口图

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

引用链接是这样的:

exports = module.exports = function(){
    //....
}

的属性exportsmodule.exports ,如函数或变量,将被暴露在外

需要注意的一点:不要override出口。

为什么呢?

因为导出仅是 module.exports 的引用,所以可以将属性添加到导出中,但是如果覆盖导出,则引用链接将断开。

好的例子 :

exports.name = 'william';

exports.getName = function(){
   console.log(this.name);
}

不好的例子:

exports = 'william';

exports = function(){
     //...
}

如果您只想公开一个函数或变量,例如:

// test.js
var name = 'william';

module.exports = function(){
    console.log(name);
}   

// index.js
var test = require('./test');
test();

此模块仅公开一个功能,并且 name 的属性是外部专有的。

当您下载并安装诸如http,sys等的 node.js 时,node.js 中有一些默认或现有的模块。

因为它们已经在 node.js 中,所以当我们想使用这些模块时,我们基本上喜欢导入模块 ,但是为什么呢?因为它们已经存在于 node.js 中。导入就像将它们从 node.js 中取出并放入程序中一样。然后使用它们。

尽管Exports恰好相反,但是您正在创建所需的模块,比如说模块 additioning.js 并将该模块放入 node.js,则可以通过导出来完成。

之前,我在这里写东西,记住,module.exports.additionTwo是一样exports.additionTwo

嗯,这就是原因,我们确实喜欢

exports.additionTwo = function(x)
{return x+2;};

小心路径

假设您已经创建了一个 additional.js 模块,

exports.additionTwo = function(x){
return x + 2;
};

在 NODE.JS 命令提示符下运行此命令时:

node
var run = require('addition.js');

这会出错说

错误:找不到模块 additional.js

这是因为由于我们未提及路径,所以 node.js 进程无法执行 additional.js。因此,我们可以使用 NODE_PATH 设置路径

set NODE_PATH = path/to/your/additon.js

现在,这应该可以成功运行,没有任何错误!!

还有一件事,您还可以通过不设置 NODE_PATH 来运行 additional.js 文件,回到您的 nodejs 命令提示符:

node
var run = require('./addition.js');

因为我们在这里通过说路径位于当前目录中来提供路径./这也应该成功运行。

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

假设有一个文件 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");

目的是:

模块化编程是一种软件设计技术,它强调将程序的功能分成独立的,可互换的模块,以便每个模块都包含执行所需功能的一个方面所必需的所有内容。

维基百科

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

试试这个例子:

fileLog.js

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

module.exports = log;

stdoutLog.js

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

module.exports = log;

程式

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

log('hello world!');

执行

$ 节点 program.js

你好,世界!

现在尝试将./stdoutLog.js交换为./fileLog.js