# JavaScript 模块化

模块化简介

什么是模块化

  • 01 将一个复杂的程序依据一定的规则拆分成单个文件,并最终组合在一起

  • 02 这些拆分的文件就是模块,模块内部数据是私有的,只是向外部暴露一些方法与外部其它模块通信

为什么需要模块化

  • 01 降低复杂度,提高解耦性

  • 02 避免命名冲突

  • 03 更好的分离,按需加载

  • 04 更高复用性,高可维护性

模块化带来的问题

  • 01 请求过多
  • 02 依赖模糊
  • 03 难以维护

模块化规范

  • 前言:
    • 一个大的项目必定会使用模块化技术,使用模块化就会使用相应的模块化规范,现在比较流行的模块化规范有以下 2 种: CommonJS、ES6

CommonJS

CommonJS 规范

暴露语法

  • 01 module.exports = value

  • 02 exports.xxx = value

  • 03 内置关系:

1657265465957

1
console.log(exports === module.exports) // true  node环境下

引入语法

  • 01 引入第三方模块 : require(xxx) , xxx 为模块名
  • 02 引入自定义模块 : require(xxx) , xxx 为模块文件的路径

module.exports 暴露

1
2
3
4
5
6
7
8
9
10
11
12
// 使用 module.exports 暴露
const data = 'atguigu'
const msg = 'hello'

module.exports = {
showData() {
console.log(data)
},
showMsg() {
console.log(msg)
},
}
1
2
3
4
5
6
7
// 导入自定义模块
const module1 = require('./module1.js')
module1.showData() // atguigu

// 也可以在导入的同时进行解构
const { showData } = require('./module1.js')
showData() // atguigu

exports 暴露

1
2
3
4
5
6
7
8
// 使用 exports 暴露
// module.exports 和 exports 不能混用,若混用了,以 module.exports 为准
exports.sum = function (a, b) {
console.log(a + b)
}
exports.sub = function (a, b) {
console.log(a - b)
}
1
2
3
4
5
6
7
8
9
// 导入自定义模块
const module2 = require('./module2.js')
module2.sum(10, 20) // 30
module2.sub(10, 20) // -10

// 也可以在导入的同时进行解构
const { sum, sub } = require('./module2.js')
sum(10, 20) // 30
sub(10, 20) // -10

引入第三方模块

1
2
3
4
5
// 引入第三方模块
const uniq = require('uniq')

let arr = [1, 5, 2, 3, 4]
console.log(uniq(arr)) // [ 1, 2, 3, 4, 5 ]

browserify 包的使用

  • 01 browserify 的作用 : 将 commonJS 规范的代码,编译成浏览器能识别解析的代码
  • 02 安装 browserify :
1
npm install browserify -g
  • 03 执行命令将 commonJS 规范的代码进行编译:
    • 会自动打包依赖
1
browserify ./app.js -o ./build.js
  • 04 在浏览器端引入生成的 build.js 文件即可

ES6 模块化规范

ES6 模块化规范

  • 01 每个文件都是一个模块。
  • 02 要借助 Babel 和 Browserify 依次编译代码,才能在浏览器端运行。
  • 03 Babel 中文网 : https://www.babeljs.cn/

暴露模块方式

  • 01 分别暴露: export 暴露内容
  • 02 统一暴露: export {暴露内容1,暴露内容2}
  • 03 默认暴露: export defalut 暴露内容:

引入模块方式

  • 01 方法 1: import {xxx,yyy} from '/module1'
  • 02 方法 2: import module3 from '/module3'

使用规则

  • 若使用分别暴露、统一暴露的方式暴露内容,那么就要用 方法 1 引入。
  • 若使用默认暴露的方式暴露内容,那么就要用 方法 2 引入。

分别暴露与导入

1
2
3
4
5
6
7
8
9
10
// 分别暴露
export const data = 'atguigu'
export const msg = 'hello'

export function showData() {
console.log(data)
}
export function showMsg() {
console.log(msg)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 导入分别暴露模块 使用方式一导入   此处不是解构赋值,因为右边不是对象,也没有赋值操作
import { showData, showMsg, data, msg } from './module1.js'
showData()
showMsg()
console.log(data)
console.log(msg)

// 导入分别暴露模块时,如果命名冲突,可以如下进行重命名,即可解决命名冲突问题
import { data as data2 } from './module2.js'
console.log(data2)

// 导入分别暴露模块时,可以打包引入, 此时 module1 是一个对象
import * as module1 from './module1.js'
module1.showData()
module1.showMsg()
console.log(module1.data)
console.log(module1.msg)
  • 编译的过程如下: 仅作了解,后面脚手架会解决这繁琐的过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 准备相关的依赖包  ES6 -> ES5
// 01 全局安装 : babel-cli 和 Browserify
// npm install babel-cli browserify -g

// 02 局部安装 babel-preset-es2015
// npm install babel-preset-es2015

// 03 定义 .babelrc 文件
// {
// "presets" : ["es2015"]
// }

// 04 编译文件
// babel ./ -d ./build

// 05 将生成的文件,再次编译成浏览器能识别的代码
// browserify ./app.js -o ./build.js

统一暴露与导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 统一暴露
const data = 'atguigu'
const msg = 'hello'

function showData() {
console.log(data)
}
function showMsg() {
console.log(msg)
}

// 统一暴露(简写,常用)
export { data, msg, showData, showMsg }
// 统一暴露(完整写法,不常用) 在导入的时候就进行重命名,此时导入的是重命名后的变量
// export { data as data, msg as msg, showData as showData, showMsg as showMsg };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 导入统一暴露模块 使用方式一导入   此处不是解构赋值,因为右边不是对象,也没有赋值操作
import { showData, showMsg, data, msg } from './module1.js'
showData()
showMsg()
console.log(data)
console.log(msg)

// 导入统一暴露模块时,如果命名冲突,可以如下进行重命名,即可解决命名冲突问题
import { data as data2 } from './module2.js'
console.log(data2)

// 导入统一暴露模块时,可以打包引入 , 此时 module1 是一个对象
import * as module1 from './module1.js'
module1.showData()
module1.showMsg()
console.log(module1.data)
console.log(module1.msg)

默认暴露与导入

1
2
3
4
5
6
7
8
9
10
11
12
// 默认暴露 适用于只暴露一个数据,一个模块不能有多个默认暴露,否则报错
export default {
name: "wc",
age: 5,
};

// 或者 二选一 一个模块不能有多个默认暴露,否则报错
const dog = {
name: "旺财",
age:5
}
export default dog
1
2
3
// 导入默认暴露模块
import dog from './module4.js'
console.log(dog)

同时使用多种暴露与导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 分别暴露
export const teacher1 = { name: '强哥', age: 15 }
export const teacher2 = { name: '歌神', age: 16 }

// 统一暴露
export const stu1 = { name: '李银河', age: 18 }
export const stu2 = { name: '张学友', age: 20 }
export { stu1, stu2 }

// 默认暴露
export default {
school: '尚硅谷',
address: '宏福科技园',
subjects: ['前端', 'java', '大数据'],
}
1
2
3
4
5
6
7
// 导入多种暴露方式的模块
import module5, { teacher1, teacher2, stu1, stu2 } from './module5'
console.log(module5)
console.log(teacher1)
console.log(teacher2)
console.log(stu1)
console.log(stu2)