JS模块化
理解模块化
什么是模块
- 将一个复杂的程序 拆分 成单个文件,最终 组合 在一起
- 拆分的 文件 就是模块,模块内部数据是私有,只是向外部暴露一些方法与其他模块通信
模块、库、包 的区别
模块(Module): javascript文件
库(Library):使用模块实现的一些 功能的统称,概念性的称呼(jQuery库,就是用于实现DOM操作)
包(Package):是依据包规范,对库功能实现的代码集合
为什么要模块化
- 降低复杂度,提高解耦性
- 避免命名冲突
- 更高的分离,按需加载
- 更高复用性,高可维护性
模块化带来的问题
- 请求过多
- 需要引入过多的文件
- 依赖模糊
- 引入文件的顺序不明确(依赖)
- 难以维护
模块化规范
应用范围
- CommonJS
- node:可以写服务端模块化代码
- browser:可以写浏览器端模块化代码
- ES6
- browser:只能写浏览器端模块化代码
模块的特性
- 引入模块时,接收的暴露数据是常量
- 多个模块组合在一起,相当于组合成一个JS文件
- 同一个组合中,对某一个模块的不同引用,获取的是同一个数据(不同组合对同一模块的引用各自独立)
- 引入模块语句,会被提升到代码的开始(CommonJS规范除外,用的是 require()函数 )
- 引入模块,会先执行模块中所有代码,然后接收暴露数据
CommonJS
规范
- 官网:http://wiki.commonjs.org/wiki/Modules
- 每个文件都是一个模块
- CommonJS 模块化的代码既可以在服务端运行,也可以在浏览器端运行
- 服务端:模块化的代码可以直接运行
- 浏览器端:模块化的代码要经过 Browserify(http://borwserify.org)编译
暴露原理
- exports 和 module.exports 在node服务端,默认都是指向同一个 空对象
- 可以为 exports 和 module.exports 指向一个 新对象
- 也可以为 exports 和 module.exports 默认指向的空对象 定义属性
module.exports.xxx = valueexports.xxx = value
- exports 和 module.exports 指向的对象,可以用 require() 函数在其他JS文件中返回 暴露对象
- 如果 exports 和 module.exports 指向不同的对象,require() 引入暴露对象,以 module.exports 为准
基本语法
- 暴露语法:
- 方法一:
module.exports = value - 方法二:
exports.xxx = value
- 方法一:
- 引入语法:
- 引入自定义模块:
require(xxx),xxx 为模块文件路径 - 引入第三方模块:
require(xxx),xxx 为模块名
- 引入自定义模块:
1 | |
浏览器端使用
原理
将 CommonJS规范 转换为浏览器可以运行的代码(转换后的代码中实现了 require() 函数)
使用方式
- 全局安装 Browserify
npm i browserify -g
- 转换 CommonJS规范
- 只需要转换 汇总 的那个 JS文件
browserify ./app.js -o ./xxx.jsbrowserify [JS文件地址] -o [输出文件名和地址]
- HTML中引入转换后的 JS文件
ES6
规范
- 每个JS文件都是一个模块
- 引入模块语句,会被提升到代码的开始
- 引入模块,会先执行模块中所有代码,然后接收暴露数据
- 浏览器如果不支持ES6语法,要借助 Babel 和 Browserify 依次编译代码,才能在浏览器端运行
- Babel 中文官网: https://www.babeljs.cn
暴露原理
ES6规范暴露的数据与CommonJS规范不同,暴露的不是对象,使用引入的语法引入的也不是一个对象,只是规定语法(虽然底层确实是对象,但是给到开发人员的并不是对象)
因此import {xxx, yyy} from "./module"其中 {xxx, yyy} 不是解构赋值
使用方式
使用ES6模块化代码有两种方式
- 浏览器支持ES6代码
- HTML引入JS文件时,script标签的type属性值必须为module
<script type="module" src="./app.js"></script>
- HTML引入JS文件时,script标签的type属性值必须为module
- 浏览器不支持ES6
- 将ES6模块化代码转换为ES5代码,script标签的type属性值就可以为text/javascript
<script type="text/javascript" src="./app.js"></script>
- 将ES6模块化代码转换为ES5代码,script标签的type属性值就可以为text/javascript
浏览器不支持ES6,想要使用 ES6 模块化代码,需要先准备相关依赖包
- 全局安装 babel-cli、Browserify
npm i babel-cli browserify -g
- 局部安装 babel ES6转ES5依赖包 babel-preset-es2015
npm i babel-preset-es2015 -S
- 定义 babel 配置文件 .babelrc
- 根目录添加文件 .babelrc
- 配置 .babelrc 文件内容
1
2
3{
"presets": ["es2015"]
}
浏览器不支持ES6,ES6模块化代码需要先使用依赖包进行编译,才能运行
- 使用 Babel 将ES6编译为ES5代码
- 进入目录
- 编译指定目录(自动编译目录中的所有JS文件,包括子目录中JS文件)
- 指定输出目录(编译完成的文件存放目录)
babel ./src -d ./build
- 使用 Browserify 将ES5汇总JS文件进行编译
browserify [JS文件地址] -o [输出文件名和地址]- ES6转ES5,模块化编程相关代码,被转成了CommonJS规范代码,需要再次编译
基本语法
- 暴露模块:
- 分别暴露:
export 暴露内容- 必须在 声明语句 前添加 export
- 统一暴露:
export { 暴露内容1,暴露内容2 }- 暴露内容 ({…}中内容)必须是 标识符
- 暴露的 标识符 可以使用 as 进行 重命名 之后暴露
- 默认暴露:
export default 暴露内容- 模块中只能有 一个 默认暴露
- 只能暴露 标识符 和 任意类型数据
- 分别暴露:
- 引入模块:
- 方法一:
import {xxx, yyy} from "./module"- 适用于 分别暴露 和 统一暴露 的数据
- 暴露数据可以配置别名
{ xxx as 别名,yyy as 别名 } - 打包引入:暴露的数据作为整体引入
import * as 别名 from "./module"
- 方法二:
import module3 from "./module3"- 适用于 默认暴露 的数据
- 方法一:
- 混合暴露
- 模块中使用不同方式进行暴露
- 引入:
import moduledefault,{xxx, yyy, aaa, bbb} from "./module"import moduledefault,* as zt from "./module"
1 | |
注意事项
引入 json 文件
如果引入一个 json 文件,会对 json 文件中的内容作为对象进行 默认暴露
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 蚂蚁图书馆!

