TypeScript import 和 require 区别

你有没有试过,写代码时明明复制了别人的代码片段,运行时却跳出“找不到模块”的报错?或者明明是同一行导入语句,在同事的编辑器里能跑,到自己电脑上就炸锅?很大概率,你遇到的是 import 和 require 的坑。这两个都是代码里用来“拉取别的文件内容”的工具,但它们就像超市的两种购物方式,看起来都是买东西,实则差了不少门道。

先搞懂最核心的区别:加载时机不一样

最容易踩的坑,就是搞不清它们什么时候干活。require 是“走到哪用到哪,当场去拿货”,属于运行时加载。比如你写 const utils = require('./utils.js'),代码运行到这一行的时候,才会打开 utils.js 文件,把里面的内容拿过来用。举个生活化的例子:你去楼下便利店买水,只有走到收银台扫商品条码的时候,才会把水的钱扣掉、把水递过来。

TypeScript import 和 require 区别

而 import 是“提前把要的东西准备好,代码刚启动就到位”,属于编译时加载,而且它必须写在代码的最顶部,不能像 require 那样塞在判断或者函数里。比如你写 import { formatDate } from './utils.js',你的代码还没开始跑,工具(比如打包工具 Webpack 或者 TypeScript 编译器)就已经把 formatDate 从 utils.js 里揪出来,存好了等着用。还是买水的例子:你提前一天就下单了便利店的水,当天去取的时候,水已经在你包里了,不用到收银台再等。

适用的场景不一样:谁更灵活,谁更省心

正是因为加载时机不同,它们适用的场景也完全不同。require 灵活到“随时可以用”,比如你需要根据不同情况导入不同的模块:如果是开发环境就加载调试工具,生产环境就加载正式工具,用 require 就能写在 if 判断里。比如:

`javascript

if (process.env.NODE_ENV === 'development') {

const debug = require('./debug.js')

debug.log('启动开发模式')

}

`

要是用 import,这行代码直接会报错——因为 import 不允许写在判断里,它必须在编译阶段就确定要加载的内容,根本不知道你运行时的环境是什么。

但 import 也有 require 比不了的好处,就是能“按需取货”。比如 utils.js 里有 10 个函数,你只需要用 formatDate 和 parseNumber,用 import { formatDate, parseNumber } from './utils',打包工具会只把这两个函数打包进你的项目,剩下的 8 个函数会被直接砍掉,最后生成的文件更小,用户加载得更快。而 require('./utils.js') 会把整个 utils.js 都拿过来,哪怕你只用到一个函数,也得背着整个文件跑。

最后要提的:它们的“出身”不一样

require 是 Node.js 的“原生宝宝”,从 Node.js 诞生那天起就有了,是 CommonJS 模块规范的一部分,之前写 Node.js 后端代码,几乎全靠它。而 import 是后来 ES6(也就是 ES2015)定的标准,本来是给浏览器前端用的,后来 Node.js 也慢慢支持了,现在前端用 React、Vue 做项目,基本都用 import。

不过现在大家写代码,经常会碰到两种模块混用的情况——比如你用 TypeScript 写代码,有时候导入老项目里的 CommonJS 模块,就得注意:import defaultForm './oldModule' 其实等价于 const oldModule = require('./oldModule'),会把整个模块当成一个整体导入;而 import * as forms from './oldModule' 才是把模块里的所有导出项拆成一个个变量,和 CommonJS 的 const forms = require('./oldModule') 结果不一样。

总结一下,不用死记硬背,记住:如果是写 Node.js 后端,或者需要动态导入的场景,用 require;如果是做前端项目,想要打包更小的体积,就用 import 准没错。

上一篇 JavaScript webpack 怎么用