模块化开发
- 一、模块化发展的过程
- 二、ES Modules 特性
- 三、ES Modules 导入导出
- 1. export import 后面的 {}
- 2. export {} 与 export default 的区别
- 3. export 导出是栈内存中的变量(原始数据类型存储的是值,对象数据类型存储的是堆内存的引用地址)
- 4. import 导入的成员是一个只读的成员,不能够修改值
- 5. import 导入路径相关
- 6. 如果不需要导入成员,只想执行所导入的模块可以省略{}, 例如可以直接写:import './module.js'
- 7. import * as 别名 from './module.js', 可以导出 module 模块 下的所有成员
- 8. 如何动态的加载模块,通过 调用全局的 import(文件路径) ,该import方法返回一个promise对象。通过then方法可以取到导出的值。
- 9. 同时导入默认成员与命名成员写法可以有两种
- 10. 可以导入导出一起使用。
- 四、ES Modules 浏览器兼容性问题
- 五、ESModules 在 Node 环境中的支持
- 六、ES Modules 在 Node 环境中与 CommonJS 的交互
- 七、ES Modules 在 Node 环境中与 CommonJS 的差异
- 八、通过babel也可以在node环境中使用ESM
一、模块化发展的过程
模块化在不同环境的使用:
浏览器环境: ES Modules 模块化规范
Node环境: CommonJS 模块化规范
二、ES Modules 特性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- script标签执行时立即执行加载脚本, defer 属性会在页面渲染完之后执行脚本 -->
<!-- 给script标签 设置type = module 来告知当前script标签中的代码采用ESM的规范来执行 -->
<!-- <script type="module"></script> -->
<!-- ESM的基本特性 -->
<!-- 1. 自动采用严格模式 -->
<script type="module">
console.log(this) // undefined
</script>
<!-- 2. 每个ESM模块都是单独的私有作用域 -->
<script type="module">
var a = 111
console.log(a)
</script>
<script type="module">
console.log(a) // ref Error
</script>
<!-- 3. ESM 的 script 标签会延迟执行脚本,默认加上了defer属性 -->
<!-- 4. ESM 是通过 CORS这种跨域请求的方式 去请求外部 JS 模块的 -->
<!-- 下面地址去请求js库会报跨域,是因为这个地址不支持 CORS, 如果要请求外部地址服务端必须支持 CORS -->
<script type="module" src="https://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<!-- 下面这个地址就没有问题,因为服务端支持 CORS -->
<script type="module" src="https://unpkg.com/jquery@3.4.1/dist/jquery.min.js"></script>
</body>
</html>
总结
- 自动采用严格模式
- 每个ESM模块都是单独的私有作用域
- ESM 的 script 标签会延迟执行脚本,默认加上了defer属性
- ESM 是通过 CORS这种跨域请求的方式 去请求外部 JS 模块的
三、ES Modules 导入导出
1. export import 后面的 {}
export import 后面的 {} 并不是字面量对象而是固定语法,与ES6的对象的简写和解构没有任何关系。
不是简写
不是解构
2. export {} 与 export default 的区别
- 通过export { m1, m2,m3 … }可以为我们导出多个成员
- export default 只可以为我们导出一个默认成员,一个模块仅允许导出一个默认成员
- export {} 和 export default 可以在一起使用
3. export 导出是栈内存中的变量(原始数据类型存储的是值,对象数据类型存储的是堆内存的引用地址)
首先我们在module.js中导出了变量name,feature ,并且在index.js中打印了他们。1秒后在module模块中修改了原始数据类型name所指向的内存空间为新的空间david(原始数据类型值为不可变的)和feature 在堆内存中hair的值为black,2秒后在index模块中打印了他们,发现index模块中的值都发生了变化。如果是值的拷贝,此时按理说是不会发生任何变化的。
4. import 导入的成员是一个只读的成员,不能够修改值
从报错信息我们得知,export 导出的成员是以常量进行声明的。所以const声明的原始数据类型不能够进行修改,引用数据类型可以修改(因为只要是栈内存存储的引用地址不发生任何的改变都不会报错)
5. import 导入路径相关
(1)必须跟上完整的导入文件路径,不能够省略文件类型。
CommonJS require() 模块的时候是可以省略文件的扩展名的
(2). import 也可以导入第三方模块需添加完整的路径,例如 https://localhost:3000/…
除了完整的路径,也可以写绝对路径
绝对路径会默认从网站的根目录下面去找,我这里起的服务是
(3)import 在浏览器环境下 不能够导入 CommonJS 提供的模块
6. 如果不需要导入成员,只想执行所导入的模块可以省略{}, 例如可以直接写:import ‘./module.js’
7. import * as 别名 from ‘./module.js’, 可以导出 module 模块 下的所有成员
8. 如何动态的加载模块,通过 调用全局的 import(文件路径) ,该import方法返回一个promise对象。通过then方法可以取到导出的值。
此时页面会报错误,请看下面代码如何动态导出成员
const age = 19
if (age > 18) {
// 如果age 》 18 我们需要导入modules.js中的所有成员
import('./modules.js').then(res => {
console.log(res, '动态导入成员')
})
} else {
// 在这里我们就可以导入另外一个模块
// import ('./modulesB.js')
}
9. 同时导入默认成员与命名成员写法可以有两种
import {name, age, default as hhh) from './module.js'
import hhh, {name,age} from './modules.js'
10. 可以导入导出一起使用。
export {name, age} from './modules.js' 。
四、ES Modules 浏览器兼容性问题
如ie浏览器目前还是没有支持这个语法
可以通过引用 browser-es-module-loader Pollyfill 来让 ie支 持es module语法
五、ESModules 在 Node 环境中的支持
目前 node.js 从 8.5版本过后已经作为实验特性支持 ES Modules的使用
1. 通过修改文件后缀名为 .mjs 的 形式,运行node 命令的时候指定命令行参数为如图
2. 在package.json 文件中指定 type = module
如果在package.json 指定了type=module 也就说当前项目模块化规范是按照ESM ,此时若想要使用 CommonJS 规范需要使用.cjs后缀才能够使用require
六、ES Modules 在 Node 环境中与 CommonJS 的交互
-
ES Modueles 中可以导入 CommonJS 模块导出的成员
-
CommonJS 中不能导入 ES Modules 所定义的导出成员
这里发生了语法错误异常的问题 -
CommonJS 始终只会导出一个默认成员也就是exports对象,多个成员是往这个对象里面添加key ,value
// 第一种
module.exports = 导出成员
// 第二种 expors 是 module.exports 的别名
// 采用此方法需要往 exports 对象中添加key value的形式来添加导出成员,注意不能够给exports重新赋值一个新对象
exports.key1 = value1
exports.key2 = value2
七、ES Modules 在 Node 环境中与 CommonJS 的差异
八、通过babel也可以在node环境中使用ESM
yarn add @babel/node @babel/core @babel/preset-env -D
配置babelrc文件,使用代码将按照哪个转换库进行转换。 babel 本身不负责任何代码的转换,他仅提供一个平台,真正进行代码转换的是@babel/preset-env, preset-env 是一个转换库的集合,里面包含了ES6+特性的语法,esmodules转换等等。