Node JS 模块:Node.js module.exports 与 exports
当我们在 javascript 中构建大型应用程序时,我们希望将其拆分为多个文件,并为这些文件提供模块。为了在我们的应用程序中使用这样的模块,我们需要导出模块中存在的类或函数。因此,在本文中,我们将研究从模块导出函数或类的两种最常见方法,即 module.exports 和 exports。我们还将研究它们之间的差异,并了解哪种方式最适合给定的情况。我们先来了解一下 javascript 中的模块
概述
当我们在 javascript 中构建大型应用程序时,我们希望将其拆分为多个文件,并为这些文件提供模块。为了在我们的应用程序中使用这样的模块,我们需要导出模块中存在的类或函数。因此,在本文中,我们将研究从模块导出函数或类的两种最常见方法,即 module.exports 和 exports。我们还将研究它们之间的差异,并了解哪种方式最适合给定的情况。
模块简介
我们先来了解一下 javascript 中的模块,可以把模块理解为一个文件,它封装了一块代码,方便应用的相关功能。模块将任何应用程序的复杂长段代码分解为更小的部分,以便于调试和管理。模块还有助于代码的可重用性。
此外,您将在Node.js遇到三种类型的模块:
- 核心模块:这些是内置模块,如 http、fs 等。
- 本地模块:这些模块由程序员在本地创建。
- 第三方模块:这些模块可在安装后使用 NPM(节点包管理器)使用,例如:express、mongoose 等。
有哪些不同的模块格式?
最初,在很长一段时间里,JavaScript 都没有模块语法的概念。这不是问题,因为最初,脚本又小又简单,所以没有必要。
但最终,脚本变得越来越复杂,因此 javascript 开发人员社区提出了各种模块格式,即将代码组织成模块的语法和按需加载模块的特殊库。让我们来看看一些流行的模块格式:
- AMD(异步模块定义):它是一种定义和使用模块的模式。它由 RequireJS 库实现,主要用于浏览器。AMD 提供了一个定义的函数来定义模块,并在应用程序中使用该模块,AMD 提供了 require 函数。
- CommonJS 格式:此模块格式由 Node.Js 实现。默认情况下,每个.js文件都是一个 CommonJS 模块。为模块提供模块变量和导出变量以公开 API。为了在应用程序中加载和使用模块,CommonJS 提供了所需的功能。
- UMD(通用模块定义):与上述两种模块格式类似,它也是一种定义和使用模块的模式,但这种模块格式的模式集使我们的代码文件在多个环境中工作。例如,UMD 格式与 AMD(异步模块定义)和 CommonJS 兼容,因此它可以在浏览器和Node.js中使用。
- ES6 (ECMAScript 6) 模块格式:在2015年,JavaScript的规范版本6引入了另一种不同的模块语法。此规范称为 ECMAScript 2015 (ES2015) 或 ECMAScript 6 (ES6)。主要语法是用于将模块导入应用程序的 import 关键字和用于从当前模块导出对象的 export 关键字。
- SystemJS 模块:它是一个可以为任何较旧的 ES 启用 ES6 模块语法的库。例如,如果当前运行时(如旧浏览器)不支持 ES6 语法。一种解决方案是将旧的模块定义转译为 SystemJS 库 API System.register 的调用。
注意:本文介绍 CommonJS 模块格式(Node.js的标准模块格式)。module.exports 和 exports 是 CommonJS 模块格式的导出关键字。
:::
为什么Node.js需要模块?
- 模块使我们的代码可重用,即我们可以定义一个模块并根据我们的需要多次使用它。
- 由于具有不同功能的不同代码存在于称为模块的不同文件中,因此维护大型代码库更容易。
- 在我们的应用程序中使用模块也有助于轻松调试代码,因为我们只需要关注导致错误的模块,而不是完整的代码。
- Node.js已经附带了一组内置模块,我们可以在代码中使用这些模块,而无需安装它们。为此,我们需要要求模块使用所需的关键字并将结果分配给变量。然后,这可用于调用模块公开的任何方法。
- 我们可以通过安装第三方软件包(它们是模块的集合)来简化我们的工作,以便在我们的应用程序中执行不同的任务,而无需自己编写代码。
Node.js中的module.exports是什么?
当我们在应用程序中调用 require 时,将创建新模块。它的初始值为空对象文本 {}。在执行引用模块的代码之前,Node.js 会用模块包装函数包装它。让我们简要地看一下模块包装函数的结构:
(function(exports, require, module, __filename, __dirname) {
// Module code lives in here
});
使用模块包装器函数,Node.js将顶级变量(使用 var、const 或 let 定义)的范围限定为模块,而不是作为全局对象。它还提供对导出的特定于模块的变量的访问,以便在我们的应用程序中使用。
模块包装函数中的变量 __filename 和 __dirname 包含模块的绝对文件名和目录路径。
通过了解模块包装器函数的结构,您一定对模块在Node.js中的工作方式有了很好的了解。
现在让我们看看 module.exports,module.exports 是我们在应用程序中进行 require() 调用时返回的对象引用。 通过模块导出,我们可以访问特定于模块的变量,这些变量不会泄漏到全局对象。
带有 module.exports 的示例程序:
msg.js
// msg.js
module.exports = {
sayHello: function () {
console.log('Hello World!');
},
sayThanks: function() {
console.log('Thank you :)');
}
}
app.js
// app.js
const msg = require('./msg')
msg.sayHello();
msg.sayThanks();
输出:
PS C:\WebApp> node app.js
Hello World!
Thank you :)
什么是Node.js出口?
好吧,您可以将导出视为模块的别名。 导出。它充当对模块的引用。 导出。使用 exports 而不是 module。exports 更方便。此外,exports 遵循解构赋值(即,它允许您从模块中提取单个导出的项目),因此我们可以选择要导入的对象。请看下面的例子来理解它:
导出示例程序:
msg.js
// msg.js
exports.sayHello = function () {
console.log('Hello World!');
};
exports.sayThanks = function() {
console.log('Thank you :)');
}
exports.sayBye = function() {
console.log('Bye!!!');
}
app.js
// app.js
const {sayHello, sayBye} = require('./msg')
sayHello();
sayBye();
输出:
PS C:\WebApp> node app.js
Hello World!
Bye!!!
解释:在上面的程序中,我们只从模块msg.js导入了应用程序app.js中的两个函数。因此,导出可以支持解构赋值。在这里,我们还观察到,我们还可以在模块中多次使用导出。
但这些是导出和模块之间的唯一区别吗? 出口?
为了理解这个问题的答案,让我们首先看一下模块对象的全部内容。
msg.js
// msg.js
console.log(module);
输出:
PS C:\WebApp> node msg.js
Module {
id: '.',
path: 'C:\\WebApp',
exports: {},
parent: null,
filename: 'C:\\WebApp\\msg.js',
loaded: false,
children: [],
paths: [ 'C:\\WebApp\\node_modules', 'C:\\node_modules' ]
}
请注意模块对象输出中的第三个属性,即 exports: {}。此属性目前是一个空对象,因为我们尚未从模块msg.js导出任何内容。在此属性中,您将找到模块的“可导入”对象。
例如:
msg.js
// msg.js
exports.sayHello = function () {
console.log('Hello World!');
};
module.exports.sayThanks = function() {
console.log('Thank you :)');
}
module.exports.sayBye = function() {
console.log('Bye!!!');
}
console.log(module);
输出:
PS C:\WebApp> node msg.js
Module {
id: '.',
path: 'C:\\WebApp',
exports: {
sayHello: [Function (anonymous)],
sayThanks: [Function (anonymous)],
sayBye: [Function (anonymous)]
},
parent: null,
filename: 'C:\\WebApp\\msg.js',
loaded: false,
children: [],
paths: [ 'C:\\WebApp\\node_modules', 'C:\\node_modules' ]
}
现在,您可以注意到 exports 属性现在有三个对象,这些对象已从模块msg.js导出。
现在让我们看一下在同一模块中使用 exports 和 module.exports 导出对象的场景。exports 将能够从模块中导出对象,直到我们将任何内容直接分配给 module.exports。让我们看一下下面的例子,以便更好地理解:
例:
// msg.js
exports.sayHello = 'Hello World!';
function sayThanks(){
console.log('Thank you :)');
}
module.exports = sayThanks;
console.log(module);
输出:
PS C:\WebApp> node msg.js
Module {
id: '.',
path: 'C:\\WebApp',
exports: [Function: sayThanks],
parent: null,
filename: 'C:\\WebApp\\msg.js',
loaded: false,
children: [],
paths: [ 'C:\\WebApp\\node_modules', 'C:\\node_modules' ]
}
解释:在上面的示例中,您可以观察到上述输出中的 exports 属性只有一个对象正在由 module.exports 导出,这意味着导出不再是对模块的引用。 导出,导出将失去导出任何对象的所有功能。
模块之间的主要区别。出口和出口
module.exports | exports |
---|---|
我们可以调用 module。在我们的模块中仅导出一次。 | 我们可以在模块中多次调用或使用导出。 |
它是从 require() 调用返回的对象引用。 | require() 不返回导出。它只是对模块的引用。出口。 |
我们不能挑选一些需要在应用程序中导入的特定对象,即我们必须导入完整的模块。 | 使用解构赋值,我们可以挑选一些需要导入到应用程序中的特定对象。 |
结论
- 模块是封装的代码块,根据其相关功能在外部应用程序中使用。
- ECMAScript 6 (ES6) 是 javascript 的官方标准模块格式。文件名的扩展名为 .mjs。
- CommonJS 是Node.js的标准模块格式。文件名的扩展名为.js。
- 模块有助于可重用、易于维护和易于调试应用程序中的代码。
- module.exports 充当从 require() 调用返回的对象引用。
- exports 几乎类似于 module.exports。它是对 module.exports 的引用。
- 导出是结构整齐的代码,外观更好,并且相对容易实现。
- exports 支持解构赋值,使用它我们可以挑选一些需要导入到应用程序中的特定对象。
- 如果将任何对象直接分配给 module. exports,则导出不能用于从该模块导出任何对象,因为它不再引用 module导出。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)