require() vs import:Node.js 模块导入对比
理解两种导入方式的核心区别
快速对比
| 特性 | require() | import |
|---|---|---|
| 加载方式 | 运行时、同步 | 编译时、静态 |
| 模块系统 | CommonJS | ES Modules |
| 提升行为 | 可在任意位置调用 | 自动提升到顶部 |
| 条件导入 | 支持 | 不支持 |
| 文件扩展名 | 可省略 | 必须写 .js |
基本语法
require()
javascript
// 导入整个模块
const fs = require('fs');
// 解构导入
const { readFile } = require('fs');
// 条件导入
if (needFeature) {
const feature = require('./feature');
feature.init();
}
// 任意位置调用
function loadModule() {
const math = require('./math');
return math.add(1, 2);
}
import
javascript
// 导入整个模块
import * as fs from 'fs';
// 解构导入
import { readFile } from 'fs';
// 默认导入
import express from 'express';
// 必须在文件顶部
import { add } from './math.js'; // 注意要写 .js
// ❌ 不支持条件导入
// if (needFeature) {
// import { feature } from './feature'; // 错误
// }
// ✅ 动态导入(返回 Promise)
if (needFeature) {
const { feature } = await import('./feature.js');
feature.init();
}
核心区别
1. 加载时机
javascript
// require - 运行时加载
console.log('before require');
const math = require('./math'); // 执行到这里才加载
console.log('after require');
// import - 编译时加载(代码执行前已完成)
console.log('before import');
import { add } from './math.js'; // 代码执行前已加载
console.log('after import');
2. 值拷贝 vs 动态引用
javascript
// counter.js (CommonJS)
let count = 0;
module.exports = { count };
count = 1; // 导出的值仍是 0
// test.js
const { count } = require('./counter');
console.log(count); // 0
// counter.js (ES Modules)
let count = 0;
export { count };
count = 1; // 导出的值同步更新为 1
// test.js
import { count } from './counter.js';
console.log(count); // 1
3. 提升行为
javascript
// require - 没有提升
console.log(add); // ReferenceError
const { add } = require('./math');
// import - 自动提升
console.log(add); // ✅ 正常工作
import { add } from './math.js'; // 实际在文件顶部执行
4. 条件导入
javascript
// require - ✅ 支持条件导入
let config;
if (process.env.NODE_ENV === 'production') {
config = require('./config.prod');
} else {
config = require('./config.dev');
}
// import - ❌ 不支持静态条件导入
// ✅ 使用动态导入替代
let config;
if (process.env.NODE_ENV === 'production') {
config = await import('./config.prod.js');
} else {
config = await import('./config.dev.js');
}
性能对比
javascript
// require - 每次调用都执行模块代码
const math1 = require('./math'); // 执行模块代码
const math2 = require('./math'); // 使用缓存,不重复执行
// import - 只执行一次,自动缓存
import { add } from './math.js'; // 执行并缓存
import { subtract } from './math.js'; // 使用缓存
使用场景
使用 require() 当:
- 需要条件导入
- 动态加载模块
- 兼容老项目
- 编写简单脚本
使用 import 当:
- 新项目开发
- 需要 tree-shaking 优化
- 使用现代框架(React、Vue)
- 跨平台代码(浏览器 + Node.js)
迁移指南
CommonJS → ES Modules
javascript
// 之前 (CJS)
const express = require('express');
const { join } = require('path');
const app = express();
module.exports = app;
// 之后 (ESM)
import express from 'express';
import { join } from 'path';
const app = express();
export default app;
实用技巧
动态导入(替代条件 require)
javascript
// 根据环境动态加载
const isDev = process.env.NODE_ENV !== 'production';
if (isDev) {
const { hot } = await import('./hot.js');
hot.enable();
}
两者互操作
javascript
// 在 ESM 中导入 CJS
import express from 'express'; // ✅ 支持良好
// 在 CJS 中导入 ESM(需要动态导入)
async function loadESM() {
const { add } = await import('./math.mjs');
return add(1, 2);
}
快速参考
javascript
// CommonJS
const { add } = require('./math');
module.exports = { value: 1 };
// ES Modules
import { add } from './math.js';
export const value = 1;
总结
- require():灵活、动态,适合复杂场景
- import:现代、静态,性能更好
新项目优先使用 import,享受更好的开发体验和工具支持!