ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

根据Node.js documentation

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

但这并没有真正的帮助。

module.exports 究竟做了什么,一个简单的例子是什么?


C
CloudBranch

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

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

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

好的答案 - 在我看来,“暴露”是比“出口”更好的术语选择
@ApopheniaOverload - 您可以执行“exports.func1、exports.func2 等”以从一个文件中获得多个公开的方法。
模块 require 应该是 var m = require('./mymodule');,带有点和斜线。这样 Node.js 就知道我们正在使用本地模块。
一定要使用: require('./module_name') 语法,因为可能有一些其他 node.js 模块具有某些名称,而不是选择您自己的模块,它会选择与 node.js 一起安装的模块
@UpTheCreek 将模块公开的公共符号称为“导出”的传统由来已久,这可以追溯到许多编程系统和几十年。这不是 Node 开发人员发明的新术语。
C
Community

这已经得到了回答,但我想补充一些说明......

您可以同时使用 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!"

this answer here 中更好地解释了 export 和 module.exports 之间的区别。


我不得不调整您的 module.exports 示例以使其正常工作。文件:var sayHello = require('./ex6_module.js'); console.log(sayHello()); 和模块:module.exports = exports = function() { return "Hello World!"; }
发现增量示例非常好,每次我对导出的操作感到超负荷时,我都会用它来刷新我的想法。
module.exports = exports = function(){...} 第二个 exports 只是一个变量,对吧?换句话说,它可以是 module.exports = abc = function()
A
Alexandre Morgaut

请注意,NodeJS 模块机制基于许多其他实现(如 RequireJSSproutCoreCouchDBWakandaOrientDBArangoDBRingoJSTeaJSSilkJS< /strong>、curl.js,甚至是 Adobe Photoshop(通过 PSLib)。您可以找到已知实现的完整列表 here

除非您的模块使用特定于节点的功能或模块,否则我强烈建议您使用 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 and CommonJS modules (caching and circular references)


A
Alexandre Morgaut

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

1. 之前附加到原始导出或 module.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. 如果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.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 设置为什么,都将始终是导出的内容。 export 变量只是 module.exports 的局部变量别名(就好像 let exports = module.exports 是每个模块的第一行)。永远不应重新分配此变量 - 这样做只会导致您失去该别名,并且不会更改导出的内容。即exports = 'abc' 不会导出'abc'。
K
K Scandrett

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

https://i.stack.imgur.com/vI2Hm.jpg

我有一个关于 module_export 的视频可用here


C
Community

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

在编写模块时记住

模块加载被缓存,只有初始调用评估 JavaScript。

可以在模块内使用局部变量和函数,并非所有内容都需要导出。

module.exports 对象也可用作 export 的简写。但是当返回一个单独的函数时,总是使用 module.exports。

根据:"Modules Part 2 - Writing modules"


q
qianjiahao

参考链接是这样的:

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

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

您必须多加注意:不要override出口。

为什么 ?

因为exports只是module.exports的引用,你可以将属性添加到exports中,但是如果你覆盖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 的属性是外部私有的。


佚名

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

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

而 Exports 正好相反,你正在创建你想要的模块,比如说模块 add.js 并将该模块放入 node.js,你可以通过导出它来做到这一点。

在我在这里写任何东西之前,请记住,module.exports.additionTwo 与exports.additionTwo 相同

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

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

小心路径

假设您创建了一个 addition.js 模块,

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

当您在 NODE.JS 命令提示符下运行它时:

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

这会出错说

错误:找不到模块添加.js

这是因为我们没有提到路径,node.js 进程无法添加.js。因此,我们可以使用 NODE_PATH 设置路径

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

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

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

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

由于我们在这里通过说它在当前目录 ./ 中来提供路径,因此它也应该可以成功运行。


a
alphadogg

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

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

派对朋友有点晚了:)
@BenTaliadoros 我也认为他迟到了,我也认为他的 anyVariable 对象有很多错误。上面的行 sayHelloInSpanish 方法不应以分号 (;) 结尾,并且 sayHelloInSpanish = function 是错误的。这个对象的所有事情都是错误的。我会编辑他的答案
编辑被禁用。 alphadogg 在这个答案中还编辑了什么?
只是格式化。除非它是我没有遇到过的一些疯狂的 es6 东西,而且我确定它不是,否则它根本不是有效的 JS
M
Moriarty

意图是:

模块化编程是一种软件设计技术,它强调将程序的功能分离为独立的、可互换的模块,这样每个模块都包含执行所需功能的一个方面所需的一切。

Wikipedia

我想如果没有模块化/可重用代码,编写大型程序会变得很困难。在 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 program.js 你好,世界!

现在尝试将 ./stdoutLog.js 换成 ./fileLog.js。


W
Willem van der Veen

模块系统的目的是什么?

它完成以下事情:

防止我们的文件膨胀到非常大的大小。在开发过程中通常很难处理包含例如 5000 行代码的文件。强制分离关注点。将我们的代码拆分为多个文件允许我们为每个文件使用适当的文件名。通过这种方式,我们可以轻松识别每个模块的功能以及在哪里找到它(假设我们创建了一个逻辑目录结构,这仍然是您的责任)。

拥有模块可以更容易地找到代码的某些部分,从而使我们的代码更易于维护。

它是如何工作的?

NodejS 使用 CommomJS 模块系统,其工作方式如下:

如果文件想要导出某些内容,则必须使用 module.export 语法声明它 如果文件想要导入某些内容,则必须使用 require('file') 语法声明它

例子:

test1.js

const test2 = require('./test2');    // returns the module.exports object of a file

test2.Func1(); // logs func1
test2.Func2(); // logs func2

test2.js

module.exports.Func1 = () => {console.log('func1')};

exports.Func2 = () => {console.log('func2')};

其他需要了解的有用信息:

模块正在被缓存。当您在 2 个不同的文件中加载相同的模块时,该模块只需加载一次。第二次在同一个模块上调用 require() 时,会从缓存中提取。模块是同步加载的。这种行为是必需的,如果它是异步的,我们无法立即访问从 require() 检索到的对象。


F
Faheel

ECMAScript 模块 - 2022

从 Node 14.0 开始,ECMAScript modules 不再是实验性的,您可以使用它们来代替 classic 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 模块。此外,它还提供了它们之间的互操作性。

模块.exports

ECMAScript 和 CommonJS 模块 have many differences 但最相关的区别 - 对于这个问题 - 没有更多的 require,没有更多的 exports,没有更多的 module.exports

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

ECMAScript 模块发布历史

发布更改 v15.3.0、v14.17.0、v12.22.0 稳定模块实现 v14.13.0、v12.20.0 支持检测 CommonJS 命名导出 v14.0.0、v13.14.0、v12.20.0 删除实验模块警告 v13.2.0、v12 .17.0 加载 ECMAScript 模块不再需要命令行标志 v12.0.0 通过 package.json "type" 字段添加对使用 .js 文件扩展名的 ES 模块的支持 v8.5.0 添加了初始 ES 模块实现

您可以在 Node.js repository 中找到所有更改日志


G
Gtm
let test = function() {
    return "Hello world"
};
exports.test = test;

这与接受答案中的第一个片段类似(return "Hello world" 没有区别),但没有任何解释。在回答之前,请确保您的回答会为主题添加一些内容。