摘要: 本教程将介绍 Node.js 模块并了解其工作原理。
Node.js 模块简介
在 Node.js 中,模块是放在 .js
文件中的可重用代码片段。Node.js 支持两种模块系统
- CommonJS
- ES 模块 (Node 14.0.0 或更高版本)。
本教程重点介绍 CommonJS 模块。
在模块中,当您定义变量、函数和类时,这些标识符只能在该模块中访问。
要将这些对象用于另一个模块,您需要使用以下导出机制之一导出它们或将它们组合起来
- 命名导出
- 默认导出。
命名导出
在命名导出中,您将标识符分配给 module.exports
对象的各个属性。这使您能够从一个模块导出多个标识符,并将它们单独导入另一个模块。
让我们看一个使用命名导出的示例。
首先,创建一个名为 math.js
的新模块,其中包含两个函数 add
和 subtract
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
Code language: JavaScript (javascript)
add
和 subtract
函数只能在 math.js
模块中看到。
要将这些函数用于另一个模块,您需要通过将它们分配给 module.exports
对象的属性来导出它们。
其次,从 math.js
模块导出 add
和 subtract
函数
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports.add = add;
module.exports.subtract = subtract;
Code language: JavaScript (javascript)
在赋值中,您使用函数名(不带括号),并将它们分配给 module.exports
对象的各个属性。
请注意,您可以在导出函数时使用不同的名称,如下所示
module.exports.sum = add;
module.exports.deduct = subtract;
Code language: JavaScript (javascript)
现在,我们在导出时将保持相同的函数名。
第三,创建一个名为 app.js
的新模块,并将 math
模块导入到 app.js
模块中
const math = require('./math');
console.log(math);
Code language: JavaScript (javascript)
要导入模块,您使用 require()
函数。require()
函数接受模块的路径,带或不带 .js
扩展名。
./
表示 math.js
模块位于与 app.js
模块相同的目录中。
控制台显示 math
是一个对象,其中包含两个函数 add
和 subtract
作为其属性
{ add: [Function: add], subtract: [Function: subtract] }
Code language: JavaScript (javascript)
最后,通过 math
对象调用 add
和 subtract
函数
// app.js
const math = require('./math');
let a = 20,
b = 5;
let result = math.add(a, b);
console.log(`${a} + ${b} = ${result}`);
result = math.subtract(a, b);
console.log(`${a} - ${b} = ${result}`);
Code language: JavaScript (javascript)
输出
20 + 5 = 25
20 - 5 = 15
Code language: JavaScript (javascript)
为了使代码更简洁,您可以在 app.js
模块中使用 对象解构,如下所示
const { add, subtract } = require('./math');
// ...
Code language: JavaScript (javascript)
在此语法中,我们将 require()
函数返回的对象的属性解构为 add
和 subtract
变量。
它等效于以下内容
// app.js
const math = require('./math');
const add = math.add,
subtract = math.subtract;
// ...
Code language: JavaScript (javascript)
默认导出
默认导出允许您从模块中导出单个标识符(变量、函数、对象 或 类)。一个模块只能有一个默认导出。请考虑以下示例
以下是如何在 math.js 模块中使用默认导出
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports = add;
Code language: JavaScript (javascript)
在此示例中,我们将 add
函数分配给 module.exports
对象,而不是其属性。这被称为默认导出。
在 app.js 模块中,您可以直接从 math.js
文件中导入 add 函数
// app.js
const add = require('./math');
let a = 20,
b = 5;
let result = add(a, b);
console.log(`${a} + ${b} = ${result}`);
Code language: JavaScript (javascript)
输出
20 + 5 = 25
Code language: JavaScript (javascript)
混合默认和命名导出
首先,使用默认和命名导出在 math.js
模块中导出标识符
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports = add;
module.exports.subtract = subtract;
Code language: JavaScript (javascript)
其次,将 add 和 subtract 函数从 math.js 导入到 app.js 模块中
const math = require('./math');
const add = math;
const subtract = math.subtract;
// ...
Code language: JavaScript (javascript)
了解模块包装器函数
在执行模块之前,Node.js 会将该模块内的所有代码包装在一个函数包装器中,如下所示
(function(exports, require, module, __filename, __dirname) {
// Module code
});
Code language: JavaScript (javascript)
例如,执行前 math.js
模块的代码将如下所示
(function (exports, require, module, __filename, __dirname) {
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports.add = add;
module.exports.subtract = subtract;
});
Code language: JavaScript (javascript)
通过这样做,Node.js 达成了以下重要目标
- 将顶层变量 (
var
、let
和const
) 的作用域保持在模块中,而不是全局对象。 - 创建一些特定于模块的变量,例如全局变量,例如
module
和exports
。
请注意,exports
对象引用了 module.exports
console.log(module.exports === exports); // true
Code language: JavaScript (javascript)
多次导入同一个模块
当您使用 require()
函数多次导入同一个模块时,require()
函数只在第一次调用时评估模块一次,并将其放入缓存中。
从随后的调用中,require()
函数使用缓存中的 exports
对象,而不是再次执行模块。
以下示例说明了它是如何工作的
首先,创建一个名为 dblogger.js
的新模块,其中包含以下代码
console.log('Connected to the DB');
Code language: JavaScript (javascript)
其次,在 app.js
中两次导入 dblogger.js
模块
let dbLogger = require('./dblogger');
dbLogger = require('./dblogger');
Code language: JavaScript (javascript)
输出
DBLogger is loaded.
Code language: JavaScript (javascript)
在此示例中,您可以看到消息 'DBLogger is loaded.'
仅出现一次,而不是两次。这意味着 Node.js 仅评估 dblogger.js
一次。
总结
- 在 CommonJS 模块中,Node.js 将 JavaScript 文件视为模块。
- 在模块中声明的所有标识符,包括变量、常量、函数和类,都作用于模块,而不是全局作用域。
- 通过将标识符分配给
module.exports
对象的属性来从模块导出标识符。 - Node.js 在执行模块之前将其模块代码包装在一个模块包装器函数中。
- Node.js 只执行一次模块,并将结果放入缓存中以备下次使用。