require: CommonJS规范,最初用于Node.js环境
import: ES6模块规范,JavaScript官方标准
| 维度 | require | import |
|---|---|---|
| 规范 | CommonJS | ES Module |
| 加载时机 | 运行时(代码执行到才加载) | 编译时(代码执行前就解析) |
| 位置限制 | 任何位置 | 必须在模块顶部 |
| 动态路径 | ✅ 支持 | ❌ 不支持(需 import()) |
| 值的性质 | 值的拷贝 | 实时只读引用 |
| Tree Shaking | ❌ 不支持 | ✅ 支持 |
// require - CommonJS 规范
const module = require('./module')
const { fn1, fn2 } = require('./module')
// import - ES Module 规范
import module from './module'
import { fn1, fn2 } from './module'require是运行时加载,代码执行到那一行才加载
import是编译时加载,代码执行前就已经加载解析
// require - 运行时加载
console.log('start')
const math = require('./math') // 执行到这里才会加载
console.log(math.add(1, 2))
// import - 静态加载(编译时)
import { add } from './math' // 代码执行前就已完成加载和解析
console.log('start')
console.log(add(1, 2))// 1. 真正的动态加载,节省资源
if (feature.isEnabled) {
const feature = require('./feature') // 不启用就不加载
}
// 2. 适合大型应用的分层加载
const middleware = []
if (env === 'dev') {
middleware.push(require('./dev-tools'))
}
// 3. 配置文件的天然支持
const config = require(`./config/${NODE_ENV}.json`)
// 4. 运行时修改模块(热替换)
delete require.cache[moduleId]
const newModule = require(moduleId) // 重新加载// 1. 无法 Tree Shaking
// 即使只用到 one 函数,整个 utils 都会打包
const utils = require('./utils')
utils.one()
// 2. 同步阻塞
const hugeLib = require('./huge-lib') // 卡住直到加载完成
// 3. 无法静态分析
// 打包工具不知道哪些模块被使用了
// 导致代码分割困难
// 4. 循环依赖可能产生不完整对象
// a.js
const b = require('./b')
module.exports = { value: 1, b }
// 此时 b 可能还是空对象// 1. Tree Shaking - 只打包使用的代码
import { debounce } from 'lodash-es'
// 只会打包 debounce,其他函数被 tree-shake 掉
// 2. 异步加载(无需额外配置)
const module = await import('./heavy-module')
// 3. 更容易做代码分割
// Webpack/Vite 能根据 import 自动分割 chunk
const AdminPage = lazy(() => import('./admin/AdminPage'))
// 4. 更好的静态分析
// IDE 能准确知道依赖关系,提供智能提示
// 可以做类型推导、自动导入等高级特性
// 5. 更容易实现变量绑定(实时引用)
// 导出的是引用,不是值拷贝// 1. 动态能力弱(需要特殊语法)
// 不能直接写变量路径
import('./locale/' + lang + '.json') // 能工作但有限制
// 打包工具会生成多个 chunk,可能不是你想要的
// 2. 严格的循环依赖检测(可能误杀合法场景)
// a.mjs
import { b } from './b.mjs'
export const a = () => b()
// 3. 加载时机固定
// 即使后面没用到,也会加载执行
import hugeLib from './huge-lib' // 一定会加载
// 4. 需要在模块顶层使用
if (true) {
import { x } from './x' // ❌ 语法错误
}
// 只能用 import() 动态导入,但那是异步的Tree Shaking 的本质是编译时静态分析,删除未使用的代码。但 CommonJS 的模块结构是动态的
require 是运行时加载,代码执行到 require 语句时才去读取、解析、执行模块。这给了它很大的灵活性——可以在任何位置调用,可以使用动态路径,可以根据条件加载。但打包工具无法做静态分析,不支持 Tree Shaking,因为模块的导出结构可能在运行时发生变化。
