Node.js 模块

摘要: 本教程将介绍 Node.js 模块并了解其工作原理。

Node.js 模块简介

在 Node.js 中,模块是放在 .js 文件中的可重用代码片段。Node.js 支持两种模块系统

本教程重点介绍 CommonJS 模块。

在模块中,当您定义变量、函数和类时,这些标识符只能在该模块中访问。

要将这些对象用于另一个模块,您需要使用以下导出机制之一导出它们或将它们组合起来

  • 命名导出
  • 默认导出。

命名导出

在命名导出中,您将标识符分配给 module.exports 对象的各个属性。这使您能够从一个模块导出多个标识符,并将它们单独导入另一个模块。

让我们看一个使用命名导出的示例。

首先,创建一个名为 math.js 的新模块,其中包含两个函数 addsubtract

function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}Code language: JavaScript (javascript)

addsubtract 函数只能在 math.js 模块中看到。

要将这些函数用于另一个模块,您需要通过将它们分配给 module.exports 对象的属性来导出它们。

其次,从 math.js 模块导出 addsubtract 函数

// 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 是一个对象,其中包含两个函数 addsubtract 作为其属性

{ add: [Function: add], subtract: [Function: subtract] }Code language: JavaScript (javascript)

最后,通过 math 对象调用 addsubtract 函数

// 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 = 15Code language: JavaScript (javascript)

为了使代码更简洁,您可以在 app.js 模块中使用 对象解构,如下所示

const { add, subtract } = require('./math');

// ...Code language: JavaScript (javascript)

在此语法中,我们将 require() 函数返回的对象的属性解构为 addsubtract 变量。

它等效于以下内容

// 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 = 25Code 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 达成了以下重要目标

  • 将顶层变量 (varletconst) 的作用域保持在模块中,而不是全局对象。
  • 创建一些特定于模块的变量,例如全局变量,例如 moduleexports

请注意,exports 对象引用了 module.exports

console.log(module.exports === exports); // trueCode 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 只执行一次模块,并将结果放入缓存中以备下次使用。
本教程对您有帮助吗?