文章目录
模块化定义
模块化是指将一个大的程序文件,拆分成许多小的文件,一个小文件就是一个模块。
然后各模块即可以相互引入,
模块的好处
没有模块化系统带来的影响
-
引入方式
没有模块化之前js代码的引入方式是通过<script src="">
标签来引入到同一个html文件中。<script src="lib.js"></script> <!-- 第三方库 --> <script src="utils.js"></script> <script src="app.js"></script>
并且两个js之前是不恒互相引入的
-
命名空间的问题:
当我们引入多个js文件,不同的js文件可能会有相同的变量名字,那么后引入的就会覆盖先引入的。即所有的js文件都是再全局空间进行定义的,每个js文件没有自己私有的命名空间。 -
依赖关系
如果按两个js文件之间有依赖关系,必须保证引入的顺序。如果文件A依赖于文件B,那么在引入时,就需要先引入文件B,再引入文件A。如果文件之间的依赖关系很复杂,这样的引入顺序就非常难以维护。
eg:没有模块化的文件引入
a.js:function a (){ console.log("我是a中的函数") }
b.js:
b = 100 a()
text.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <script type='text/javascript' src='./a.js'></script> <script type='text/javascript' src='b.js'></script> <script type='text/javascript'> </script> </body> </html>
浏览器输出:
我是a中的函数
如果先引入b.js再引入a.js,就会报错
a未定义
使用模块化之后,就可以在b.js
文件中引入a.js
文件,避免了依赖引入的问题,同时可以确保依赖加载的顺序是先加载a.js
,再加载b.js
模块化的优点
- 防止命名冲突,每个模块都有自己的命名空间
- 代码复用,每个模块可以被其他多个模块引用
- 高维护性,修改一个模块其他引用该模块的地方都改变
- 确保引入顺序的正确性,使用模块化之后一般都是在自己的中引入所依赖的模块,所以避免了依赖顺序的引入问题
模块化规范及对应的产品
模块化规范 | 产品 |
---|---|
CommonJS | NodeJS、Browserify(前端打包工具) |
AMD | requireJS |
CMD | seaJS |
ES6模块化的语法
模块功能主要由两个命令构成:export和 import
export
命令用于规定模块的对外接口import
命令用于输入其他模块提供的功能(导入功能)
eg:
m1.js:
// export将功能暴露出去
export let name = "孙悟空"
export function wuqi (){
console.log('我的武器是金箍棒')
}
html:
注意script设置type="module"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模块化</title>
</head>
<body>
<script type="module">
// 将m1.js中所有暴露的内容全都存在变量m1中
import * as m1 from "./m1.js"
console.log(m1)
</script>
</body>
</html>
输出:
ES6暴露模块export
分别暴露
在要暴露的数据前面添加export
,就是上面的例子
// export将功能暴露出去
export let name = "孙悟空"
export function wuqi (){
console.log('我的武器是金箍棒')
}
统一暴露
暴露也可以写成一行
格式:export{要暴露的变量名}
m2.js:
// export将功能暴露出去
let name = "猪八戒"
function wuqi (){
console.log('我的武器是铁耙子')
}
export{name,wuqi}
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模块化</title>
</head>
<body>
<script type="module">
// 将m1.js中所有暴露的内容全都存在变量m1中
import * as m1 from "./m1.js"
import * as m2 from "./m2.js"
console.log(m2)
</script>
</body>
</html>
默认暴露
默认暴露只能暴露一个对象。
格式:
// 默认暴露
export default {
要暴露的数据(对象格式)
}
该种方法的返回值是一个default对象,调用里面属性的时候的时候需要添加.default
eg:
m3.js
// 默认暴露
export default {
name:"猪八戒",
wuqi:function(){
console.log('我的武器是铁耙子')
}
}
html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模块化</title>
</head>
<body>
<script type="module">
// 将m1.js中所有暴露的内容全都存在变量m1中
import * as m1 from "./m1.js"
import * as m2 from "./m2.js"
import * as m3 from "./m3.js"
console.log(m3)
m3.default.wuqi()
</script>
</body>
</html>
ES6暴露引入模块import
通用导入方式
格式:import * as 变量名 from "js文件地址"
就是上面使用的方式,该方式可以应对所有暴露方式
eg:
import * as m1 from "./m1.js"
解构赋值形式
-
应对分别暴露、统一暴露
格式:import {解构赋值的变量名} from "js文件地址"
解构赋值的变量名
对应着js暴露出去的变量//分别暴露 import {name,wuqi} from "./m1.js" console.log(name) console.log(wuqi) // 统一暴露 import {name as zhubajie,wuqi as tiepazi} from "./m2.js" console.log(zhubajie) console.log(tiepazi)
-
应对默认暴露
import {default as m3} from "./m3.js" console.log(m3)
简便形式(只针对默认暴露)
简便形式只针对默认暴露:
格式:import 变量名 from 'js地址'
EG:
import m3 from './m3.js'
console.log(m3)
模块化引入
之前我们模块的引入都是在script中写的,一般情况下我们习惯把所有的模块引入放到一个JS文件中,叫做入口文件,然后html再引入该文件
eg:
app.js
// 入口文件
import * as m1 from "./m1.js"
import * as m2 from "./m2.js"
import * as m3 from "./m3.js"
console.log(m1)
console.log(m2)
console.log(m3)
html引入(不要忘记type设置成module,因为main.js是一个模块化文件,所以引入的时候需要添加type=module
来指明这是一个模块化文件)
<script src="./app.js" type="module"></script>
输出:
模块代码在项目中的使用
由于ES6语法较新,浏览器不能直接理解,所以要将ES6语法转化成较低版本的语法,共浏览器理解。我们就需要使用Babel工具来帮助我们转化。
Babel简介
babel是js的一款编译器可以将比较新的js语法转换成ES5语法。
官网:https://babel.docschina.org/
转完之后将代码进行打包,页面在进行引入就可以解决兼容性问题
Babel使用
-
安装以下工具
- babel-cli(babel命令行)
- babel-preset-env(将比较新的js语法转换成ES5语法)
- browserify(webpack)(打包工具)
安装语句:
npm init -yes
(初始化)
npm i babel-cli babel-preset-env browserify -D
(安装)
-
进行转换
转换命令:
npx babel 要转换的文件目录 -d 要生成的文件目录 --presets=babel-preset-env
eg:npx babel src/js -d dist/js
-
打包
npx browserify 要打包的文件地址 -o 要生成的文件目录/要生成的文件.js
eg:npx browserify dist/js/app.js -o dist/bundle.js
html在引入的时候就引入
打包好的
文件。
ES6模块化第三方模块
以jquery为例
- 下载juery包:
npm i jquery
- 使用juery包:
再js文件中引入:import $ from 'jquery';
//等价于const $ = require("jquery");
这样再js文件中就可以使用jQuery语法编写语句了。
ES6模块和CommonJS模块的区别
- 导入导出模块的方式不同:CommonJS使用require(导入)和module.exports/exports(导出),而ES6模块使用import(导入)和export(导出)。
- 加载机制不同:CommonJS模块是
在运行时加载
,而ES6模块是在编译时就解析完成依赖关系
。 - 兼容性:由于Node.js的广泛应用,CommonJS模块兼容性相对较好,但需要使用工具如
Webpack
和Babel
进行打包构建才能应用在浏览器端。ES6模块对于新版浏览器兼容性较好,旧版浏览器则需要借助Babel
进行转译。 - 引用不同:CommonJS模块导出module.exports的值实际上是一个值的拷贝,就算原对象改变,导出的值不会改变;import得到的是一个值的引用,原对象改变,导出的值也会改变。
- 使用场景:ES6模块可以在html文件中使用
<script>
标签引用,但是需要添加type = module
属性,这会告诉浏览器你的脚本是一个JavaScript模块,而非一个传统的全局作用域的脚本,type="module"的脚本默认采用异步加载(相当于在<script>
标签上加了一个async属性)。
模块的异步加载和同步加载
参见: https://blog.csdn.net/mantou_riji/article/details/137072904