什么是模块化开发
- 将一个项目按照功能划分,理论上一个功能一个模块,互不影响,在需要的时候载入,尽量遵循高内聚低耦合
模块化演变过程
- 文件引用
- 简单的将所有的js文件统统放在一起。但是这些文件的顺序还不能出错,比如jquery需要先引入,才能引入jquery插件,才能在其他的文件中使用jquery。
- 污染全局作用域,会导致全局变量命名冲突,依赖关系不明显,后期维护成本较高
- 包裹全局对象
- 设置模块成员的命名空间,只解决了命名冲突
- 设置模块成员的命名空间,只解决了命名冲突
- IIFE (立即执行函数)
- 闭包实现了私有成员,外部无法访问,清楚依赖关系
- 闭包实现了私有成员,外部无法访问,清楚依赖关系
模块化的意义
- 解决命名冲突
- 管理依赖
- 提高代码的可复用性
模块化规范
CommonJS 规范 (同步模式加载模块)
- nodejs中提出的标准,一个文件就是一个模块,每个模块都有独立的作用域,通过module.exports导出成员,通过require函数载入模块.
- 问题:
- 在浏览器端使用的话,启动时加载模块,每次页面加载都会有大量同步模式请求出现,效率低下
AMD
-
AMD 使用起来相对复杂,模块JS文件请求频繁. Require.js实现了AMD规范
-
define 函数 定义模块
-
图中 第一个参数是模块的名字,
-
第二个参数是数组 依赖项,
-
第三个参数是函数跟依赖项一一对应,这个函数的作用是为了给当前模块提供私有的空间,向外部导出成员的方式 return 即可
-
-
require 函数 加载模块
CMD规范 Sea.js实现了CMD规范
现阶段的规范统一
ES Modules
-
目前多数的浏览器已经支持了ES Modules 可以直接通过Script去加载 设置type=module
-
有以下特点:
-
每个module都运行在单独的私有作用域
-
默认是严格模式无法使用this,严格模式下是undefined
-
通过CORS 方式请求外部js模块
-
自动延迟执行脚本等同于script标签的defer属性一样
-
-
ES Modules 核心功能
-
import export 导入导出
-
导入的成员变量是引用导出的成员存放的内存地址.
-
导入的成员的是只读的
-
导入可以省略 index.js,会自动加载目录下的index.js
-
必须是./开头 或者 /开头 根目录查找,字母开头会以为是第三方模块
-
导出的成员不是字面量对象,花括号只是语法
-
export default xxx
-
import 默认成员,{ 特定成员} from './xxx.js'
-
as xxx 导出/导入成员重命名
-
import xxx.js/import {} from './xxx.js' 直接执行模块
-
import * as a from './xxx.js' 可以拿到全部成员
-
-
-
ES Modules 在node中的使用
-
默认commonjs规范下运行ESModule,修改文件扩展名.mjs
node --experimenal-modules xxx.mjs
- package.json 增加 type:module,可以直接执行
node --experimenal-modules xxx.js
- .cjs 告知是commonjs规范
node --experimenal-modules xxx.cjs
- package.json 增加 type:module,可以直接执行
兼容性支持
polyfill
- 添加polyfill让浏览器支持最新语法,动态编译脚本,生产阶段不使用,浪费资源
babel
- babel 是以插件形式实现的,不会转换代码.需要插件转换特性,一个插件转换一个特性
- 安装babel yarn add @babel/node @babel/core @babel/preser-env --dev
- 使用 yarn babel-node xxx.js --presets@babel/preset-env
- presets 是一个插件集合,可以在.babelrc文件中配置,也可以在命令行中输入命令参数