Node.js module.exports
的用途是什么?您如何使用它?
我似乎找不到任何关于此的信息,但它似乎是 Node.js 的一个相当重要的部分,因为我经常在源代码中看到它。
module 对当前模块的引用。特别是 module.exports 与导出对象相同。有关更多信息,请参阅 src/node.js。
但这并没有真正的帮助。
module.exports
究竟做了什么,一个简单的例子是什么?
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
的结果(通常)如何只是一个可以访问其属性的普通对象。
注意:如果您覆盖 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
这已经得到了回答,但我想补充一些说明......
您可以同时使用 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
简单来说,您可以将所需文件视为返回单个对象的函数,并且您可以通过在 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 之间的区别。
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()
请注意,NodeJS 模块机制基于许多其他实现(如 RequireJS、SproutCore、CouchDB、 Wakanda、OrientDB、ArangoDB、RingoJS、TeaJS、SilkJS< /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))
如果将新对象的引用分配给 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() {};
let exports = module.exports
是每个模块的第一行)。永远不应重新分配此变量 - 这样做只会导致您失去该别名,并且不会更改导出的内容。即exports = 'abc'
不会导出'abc'。
module.exports 属性或exports 对象允许模块选择应该与应用程序共享的内容
https://i.stack.imgur.com/vI2Hm.jpg
我有一个关于 module_export 的视频可用here
将程序代码划分为多个文件时,module.exports
用于将变量和函数发布给模块的使用者。源文件中的 require()
调用被替换为从模块加载的相应 module.exports
。
在编写模块时记住
模块加载被缓存,只有初始调用评估 JavaScript。
可以在模块内使用局部变量和函数,并非所有内容都需要导出。
module.exports 对象也可用作 export 的简写。但是当返回一个单独的函数时,总是使用 module.exports。
根据:"Modules Part 2 - Writing modules"。
参考链接是这样的:
exports = module.exports = function(){
//....
}
exports
或 module.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');
由于我们在这里通过说它在当前目录 ./
中来提供路径,因此它也应该可以成功运行。
模块将相关代码封装成单个代码单元。创建模块时,这可以解释为将所有相关功能移动到文件中。
假设有一个 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
组合我们的程序。
试试这个例子:
文件日志.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。
模块系统的目的是什么?
它完成以下事情:
防止我们的文件膨胀到非常大的大小。在开发过程中通常很难处理包含例如 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() 检索到的对象。
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 中找到所有更改日志
let test = function() {
return "Hello world"
};
exports.test = test;
return "Hello world"
没有区别),但没有任何解释。在回答之前,请确保您的回答会为主题添加一些内容。