一、演变过程
stage 1 文件划分方式
- 如何做:约定一个文件就是一个模块,用script标签引入
- 缺点
- 污染全局作用域
- 命名冲突问题
- 无法管理模块间的依赖关系
- 完全依靠约定
stage 2 命名空间方式
- 如何做,在stage1的基础上,约定所有模块暴露一个全局对象,所有成员都挂载到对象上
- 缺点
- 没有私有空间,成员可以被修改
stage 3 使用立即执行函数
- 提供私有作用域,对于需要暴露的成员,可以使用挂载到全局作用域上的方式暴露,实现了私有作用域
stage 4 传入参数
- 还可以传入参数,可以表现出每个模块之间的依赖关系
二、模块化规范
为什么需要模块化规范,上面的加载方式都是通过script的方式引入,模块可能删除仍然引入,我们需要一个自动加载模块的基础库
模块化规范 + 模块加载器
1.commonjs
- 一个文件就是一个模块
- 每个模块都有单独的作用域
- 通过module.exports导出模块
- 通过require函数载入模块
- 是同步加载,启动时加载模块,执行过程不需要加载模块,仅使用。
2.amd+require.js
- 异步的模块定义规范
- require.js实现了amd,本身还是一个模块加载器
- 编写复杂,模块划分细的话,请求会变多
3.sea.js + cmd
4.es module
三、es module
1.特性
- script标签增加type=module
可以用一个叫serve的工具去启动一个npm终端,web服务器,或者open live serve
- 会自动采用严格模式
- 每个es module都是运行在单独的私有作用域中
- esm 是通过cors的方式请求外部js模块,不支持文件的形式去访问,得用http的serve
- 会自动延迟执行脚本
2.导入导出
browser-sync模块,带热更新的
- 模块尾部导出,可以重命名
- 默认导出的成员,导入的时候必须要重命名
- 默认导出,可以直接使用一个变量名的方式直接导出,变量名任意
3.导入导出注意事项
- 导出export {} 也不是导出一个对象,不是字面量对象,
- 导入import也不是对象解构,而是一种固定语法,export单独使用的时候,必须用花括号,如果要导出一个对象用export default,可以跟变量,可以跟值
- 导出的成员是只读的引用,不是值
4.import的用法和特点
- from后面必须要带上文件的扩展名
- index文件也是需要完整路径的
- 相对路径的./ 也不能省略,不然以为是引用第三方模块
- 也可以使用绝对路径或者完整url引入模块
- 直接执行模块
- 使用*导出所有成员放入一个对象里面
- 动态导入,满足条件再导入文件,import只能在最顶层使用,promise
- 导出默认&具名成员同时导出
5.直接导出导入成员
- 导入结果直接作为当前模块的导出成员
- 导出default需要重命名
四、polyfill兼容方案
github
- 在不支持esmodule的浏览器执行
五、node中的esmodule
1.node中运行esmodule
高版本可以直接运行不需要参数
- 可以通过import导入内置模块
- 第三方模块都是导出一个对象,必须用默认导入的方式导出成员
- 内置模块可以,做了兼容
2.esmodule中导入commonjs模块
- commonjs导出始终只会导出一个一个默认成员
3.commonjs导入esmodule
- node中是不支持的
4.node环境中使用esmodule和commonjs的差异
5.新版本支持es
这样就不需要mjs了,但是需要cjs,反过来也是一样的