1. 为什么会出现 commonjs 和 ESModule?
早期 JavaScript 模块这一概念,都是通过 script 标签引入 js 文件代码。当然这些基本简单需求没有什么问题,但当我们的项目越来越庞大时,我们引入的 js 文件就会越多,这时就会出现以下问题:
- js 文件作用域都是顶层,这会造成变量污染
- js 文件多,变得不好维护
- js 文件依赖问题,稍微不注意顺序引入错,代码全报错
为了解决以上问题 JavaScript 社区出现了 CommonJs,CommonJs 是一种模块化的规范,包括现在的 NodeJs 里面也采用了部分 CommonJs 语法在里面。那么在后来 ES6 版本正式加入了 ESModule 模块,这两种都是解决上面问题:
- 解决变量污染问题,每个文件都是独立的作用域,所以不存在变量污染
- 解决代码维护问题,一个文件里代码非常清晰
- 解决文件依赖问题,一个文件里可以清楚的看到依赖了那些其它文件
2. commonjs 和 ESModule 对比
commonjs:
CommonJs可以动态加载语句,代码发生在运行时- 导出使用
exports或者module.exports。使用exports导出之后就不能再导出一个对象值,导出也无效。 commonJS的导出值是拷贝,可以修改。
commonJs 解决上面的 变量污染 和 文件依赖 问题,并且不可以重复导入。
ESModule:
ESModule是静态的,只能声明在文件的最上面。- 使用
export或者export default混合使用 - 导出值是映射关系 ,值是只读的不能修改。
ESModule 也 解决上面的 变量污染 和 文件依赖 问题,并且更灵活,导出的值是引用,是可读状态,增强代码的可读性性。
3. import 和 require 的对比
1. import 静态使用
import 指令会被 js 引擎静态分析,会先于模块内的其它语句执行。
// 所以下面的代码会报错
// Error
if(condition){
import module from './module'
}
⚠️ 注意:引擎处理 import语句是在编译阶段,这时并不会去分析或执行 if 语句,所以 import 语句放在 if 代码块之中毫无意义,因此会报句法错误,而不是执行时错误。也就是说,import 和 export 命令只能在模块的顶层,不能在代码块之中。
2. import 的动态使用
import 作为静态资源加载的话,有利于提高编译的效率。但是却无法实现在运行时加载模块。就无法实现条件加载,要用 import 取代 Node 的 require() 的话就行不通,因为 require() 是在运行时加载模块,import 无法实现动态加载。比如:
// 动态加载,只有在运行的时候才知道加载的是什么
const path = './' + fileName;
const module = require(path);
于是有人提案,引入 import() ,实现动态加载。
import(module)
import() 返回一个 promise 对象。可以结合 Promise 使用。
3.import 和 import() 的区别
import() 函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。另外,import() 函数与所加载的模块没有静态连接关系,这点也是与 import 语句不相同。
4.import() 和 require() 的区别
import() 是异步加载,require() 是同步加载