模块化
定义:
将程序划分为一个个小的结构体 有自己的代码逻辑 也会有自己的作用域。在es6之前 都是用AMD CMD CommonJS(支持node) 直到es6出现后 有了ESmodule
在没有模块化解析的时候 虽然利用了函数本身自带的作用域并且使用了闭包来区分各个模块 但是这种办法会有缺陷
- 函数名有可能会重复
- 命名不好管理
- 要记得每一个模块的名字
AMD 应用于浏览器的一种模块化规范 异步加载
1.概念
- AMD是Asynchronous Module Definition(异步模块定义)的缩写
- 它采用的是异步加载模块
- 事实上AMD规范要早于CommonJS 但是CommonJS目前依旧被使用(基本上node环境) AMD已经使用的很少了
- AMD实现基于require.js库和curl.js库 这两个库git hub作者已经有2-3年没有更新过代码了 2.使用
- 引入require.js
- data-main属性的作用是在加载完src的文件后会加载执行该文件
CMD 应用于浏览器的一种模块化规范 异步加载
1.概念
- CMD是Common Module Definition(通用模块定义)的缩写
- 他也采用了异步加载模块 但是它将CommonJS的优点都吸收了过来
- 目前CMD也很少有人使用了
- 他基于SeaJS库 2.使用
- 引入SeaJS
- seaJS是指定主入口
CommonJS 规范 同步加载
表现形式
- Node是CommonJS在服务端具有代表的实现
- Browserify是CommonJS在浏览器中一种实现
- webpack 打包工具对CommonJS的支持和转换
导出和导入
exports 和 module.exports都是负责对模块进行导出
require函数可以帮助我们导入其他模块(自定义模块,系统模块,第三方库模块)中内容
在node中 读取node核心模块 const fs = require('fs')寻找过程const nmu=require(./abc) - 如果有后缀名: 他会找对应文件下自动去找后缀名为index.js的文件
- 如果没有后缀名: 他会先去寻找abc文件 再去查找abc.js文件 再去寻找abc.json文件 最后找abc.node文件
- 如果不是核心业务模块:他会依次在每一层的node modules 寻找你引入的模块
- 如果都没找到 他会报 not found 模块的加载过程
- 在模块被第一次引用的时候 模块化中js会被运行一次(因为他得看模块代码中是否还有其他模块的引用一次寻找)
- 在第一次运行完的时候 他会被加入缓存里面 这样以后有其他地方导入 可以直接走缓存,在node源码每一个js都有一个modules实例 在实例里面记录了一个变量loading 当第一次加载完毕 这个变量会变成true
- 当模块互相被引用的时候 就会形成一个图结构 在图结构遍历的过程中 他有两种方式 1.深度优先搜索算法(DFS)会优先一条路径走到底 2.广度优先搜索算法(BFS)会发散引用 从各个方向去引用
CommonJS 不适合在浏览器中 因为浏览器需要先从服务器中将导入的文件下载下来 之后再加载运行比较适合node端 也可以使用browserify 这个异步加载
exports和module.exports的区别 exports.name='1234' module.exports={name:'123123'} 在底层实现上 module.exports={} 在最后他会有 exports=module.exports这个步骤所以 他俩用法都相等 但是这种事错误的写法 exports={name:'213'} 因为他把exports指向了一个新的对象 而不是原来的module.exoports了
ES Module 异步加载
定义:
- 它使用了import和export
- 它采用了编译期的静态分析 并加入了动态引入
- 如果脱离了webpack的编译的话 需要在html引入的 正常情况下哎单纯的解析js 他是不是别import关键字的 所以需要在标签上加上type=‘module’
具体使用
export
1.export 跟上声明语句
export const name =12
2.export 跟上导出
export{
name,
age
}
3.导出的时候起别名
export{
name as fname,
age as fage
}
4.默认导出
export default foo
export{
name as default,
}
import
1.普通导入
import {name} from './模块化.js'
2.起别名
import {name as fname,age as fage} from './模块化.js'
3.导出的所有内容放到一个标识符
import \* as foo from './模块化.js'
4.默认导出
import why from './模块化.js'
import 函数 他不会堵塞后续代码执行(异步) 他返回的是一个 promise
import("./模块化.js").then(res=>{
console.log(res)
})
import.meta 这是ES11新增的属性 获取你当前文件的下载路径
ESmodule的加载流程
-
阶段一:构建阶段 查找到服务器中的js文件地址 并且下载浏览器里面的文件 将其解析成模块记录吧(数据结构) 他是一个静态分析过程 做好不要在逻辑代码里面使用 他会生成一个module record的数据结构 来解析是否继续依赖其他文件,当一个文件被多处依赖的时候 他不会进行多次下载 当他在第一次加载下载的的时候 在浏览器会进行一个map的映射关系进行缓存 请求一次后会加入里面
-
阶段二:实例化 对模块记录进行实例化,并且分配内存空间,解析模块的导入和导出语句 把模块指向对应的内存地址 但是内部值都是undefined 还没有赋值
-
阶段三:运行 运行代码 填入值 并且将值填充到内存地址中
只有导出的地方可以修改这个值 但是在导入的地方无法修改值 CommonJs和es module相互调用 1.在浏览器中 他俩不可以互相调用 在浏览器里面默认不支持commonJs的 他会报未定义common的 2.在node中需要区分node版本 在老版本是不支持es module的 需要加上ejs的 在新版本还是慢慢开始支持es module 3. 平时开发(基于webpack) 他是完全支持的