JavaScript 有个特点:大量常用功能是全局可用的。Math、Array、Map、Set、console、JSON 这些直接就能用,不需要导入。和 Python、Java 比起来,你需要手动 import 的东西其实不多。
不过在 Node.js 环境中(LeetCode 和本站的 JS 运行环境都是 Node.js),有些模块还是需要用 require 来加载的。这篇文章来讲讲 JavaScript 的模块系统。
Node.js 模块系统(CommonJS)
Node.js 使用 CommonJS 模块规范,核心就两个东西:
- 用
require()导入模块 - 用
module.exports导出内容
// 导入内置模块
const os = require('os');
// 导入自定义文件
const utils = require('./utils');
// 导入第三方包
const { PriorityQueue } = require('@datastructures-js/priority-queue');导入自定义文件时,路径要以 ./ 或 ../ 开头,表示相对路径。不加前缀的话,Node.js 会去 node_modules 目录找第三方包。
刷题常用模块和内置对象
JavaScript 很多常用功能是全局可用的,不需要 import:
| 全局对象 | 用途 |
|---|---|
Math | 数学函数(max、min、floor、ceil、abs、sqrt) |
JSON | JSON 解析(parse、stringify) |
Array、Map、Set | 内置数据结构 |
parseInt、parseFloat | 类型转换 |
console.log | 输出 |
需要 require 导入的:
| 模块 | 用途 | 导入方式 |
|---|---|---|
readline | ACM 模式读取标准输入 | require('readline') |
@datastructures-js/priority-queue | 优先队列(LeetCode/本站预装) | require('@datastructures-js/priority-queue') |
具体的用法和示例会在后续的 常用数据结构 和 算法题常用技巧 章节中详细介绍。
ES6 模块(了解即可)
除了 CommonJS,JavaScript 还有一套更现代的模块系统叫 ES6 模块(ESM),用 import/export 语法:
// 导出
export function add(a, b) { return a + b; }
export default class Calculator { ... }
// 导入
import { add } from './math.js';
import Calculator from './calculator.js';ES6 模块和 CommonJS 的主要区别:ES6 是静态导入,在编译时就确定了依赖关系;CommonJS 是动态加载,运行时才去找模块。
目前大多数 OJ 平台和 LeetCode 的 JavaScript 环境仍然用 CommonJS(require),所以你刷题时用 require 就行。了解 ES6 模块主要是为了以后写前端项目时用。
导出模块内容
在 CommonJS 中,一个文件要对外提供函数或变量,需要通过 module.exports 导出:
// math_utils.js
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
function isPrime(n) {
if (n < 2) return false;
for (let i = 2; i * i <= n; i++) {
if (n % i === 0) return false;
}
return true;
}
// 把要导出的函数挂到 module.exports 上
module.exports = { factorial, isPrime };其他文件就可以 require 进来使用了:
// main.js
const { factorial, isPrime } = require('./math_utils');
console.log(factorial(5)); // 120
console.log(isPrime(7)); // true下面是一个完整的多文件项目示例:
了解了模块和导入之后,下一篇我们来讲 函数与闭包。函数是 JavaScript 中组织代码的核心手段,箭头函数和闭包也很有特色,学完之后你就能写出更有结构的代码了。