1. 模块化概述
1.1. 什么是模块化?
- 就是将程序文件依据一定规则
拆分成多个文件, 这种编码 方式就是模块化的编码方式 - 拆分出来
每个⽂件就是⼀个模块,模块中的数据都是私有的,模块之间互相隔离。 - 同时也能通过⼀些⼿段,可以把模块内的指定数据“
交出去”,供其他模块使⽤。
1.2. 为什么需要模块化
随着应用的复杂度越高, 我们的其代码和文件数量都会急剧增加, 会逐渐引发以下问题:
- 全局污染问题
- 依赖混乱问题
- 数据安全问题
2. 有哪些模块化规范?
历史背景(了解即可):2009 年,随着 Node.js 的出现,JavaScript 在服务器端的应⽤逐渐增
多,为了让 Node.js 的代码更好维护,就必须要制定⼀种 Node.js 环境下的模块化规范,来⾃
Mozilla 的⼯程师 Kevin Dangoor 提出了 CommonJS 规范(CommonJS 初期的名字叫
ServerJS),随后 Node.js 社区采纳了这⼀规范。
随着时间的推移,针对 JavaScript 的不同运⾏环境,相继出现了多种模块化规范,按时间排序,
分别为:
3. 导⼊与导出的概念
模块化的核⼼思想就是:模块之间是隔离的,通过导⼊和导出进⾏数据和功能的共享。
-
导出(暴露):模块公开其内部的⼀部分(如变量、函数等),使这些内容可以被其他模块使⽤。
-
导⼊(引⼊):模块引⼊和使⽤其他模块导出的内容,以重⽤代码和功能
4. CommonJS 规范
4.1 初步体验
-
1.「创建 school.js」
const name = 'NFIT' const slogan = '珠海欢迎您' function getTel() { return '101-56133123' } function getCities() { return ['北京','上海','深圳','成都','武汉','⻄安'] } // 通过给exports对象添加属性的⽅式,来导出数据(注意:此处没有导出getCities) exports.name = name exports.slogan = slogan exports.getTel = getTel -
2.「创建 student.js」
const name = '张三' const motto = '相信明天会更好!' function getTel (){ return '13877889900' } function getHobby(){ return ['抽烟','喝酒','烫头'] } // 通过给exports对象添加属性的⽅式,来导出数据(注意:此处没有导出getHobby) exports.name = name exports.slogan = slogan exports.getTel = getTel -
3.「创建 index.js」
// 引⼊school模块暴露的所有内容 const school = require('./school') // 引⼊student模块暴露的所有内容 const student = require('./student')
4.2 导出数据
在 CommonJS 标准中,导出数据有两种⽅式:
-
第⼀种⽅式: module.exports = value
-
第⼆种⽅式: exports.name = value
注意点如下:
- 每个模块内部的: this 、 exports 、 modules.exports 在初始时,都指向同⼀ 个空对象,该空对象就是当前模块导出的数据,如下图:
⽆论如何修改导出对象,最终导出的都是 module.exports 的值。
exports 是对 module.exports 的初始引⽤,仅为了⽅便给导出象添加属性,所以
不能使⽤ exports = value 的形式导出数据,但是可以使⽤ module.exports
= xxxx 导出数据。
4.3. 导⼊数据
在CJS模块化标准中,使⽤内置的 require 函数进⾏导⼊数据
// 直接引⼊模块
const school = require('./school')
// 引⼊同时解构出要⽤的数据
const { name, slogan, getTel } = require('./school')
// 引⼊同时解构+重命名
const {name:stuName,motto,getTel:stuTel} = require('./student')
4.4 扩展理解
⼀个 JS 模块在执⾏时,是被包裹在⼀个内置函数中执⾏的,所以每个模块都有⾃⼰的作⽤域,我
们可以通过如下⽅式验证这⼀说法:
console.log(arguments)
console.log(arguments.callee.toString())
内置函数的⼤致形式如下:
function (exports, require, module, __filename, __dirname){
/*********************/
}
4.5 浏览器端运行
Node.js 默认是⽀持 CommonJS 规范的,但浏览器端不⽀持,所以需要经过编译,步骤如下:
-
第⼀步:全局安装 browserify : npm i browserify -g
-
第⼆步:编译
browserify index.js -o build.js备注: index.js 是源⽂件, build.js 是输出的⽬标⽂件
-
**第三步: **⻚⾯中引⼊使⽤
<script type="text/javascript" src="./build.js"></script>
5. ES6 模块化规范
ES6 模块化规范是⼀个官⽅标准的规范,它是在语⾔标准的层⾯上实现了模块化功能,是⽬前最
流⾏的模块化规范,且浏览器与服务端均⽀持该规范。
5.1 初步体验
-
1.「创建 school.js」
// 导出name export let name = {str:'NFIT'} // 导出slogan export const slogan = '欢迎来到广东!' // 导出name export function getTel (){ return '010-56253825' } function getCities(){ return ['北京','上海','深圳','成都','武汉','⻄安'] -
2.「创建 student.js」
// 导出name export const name = '张三' // 导出motto export const motto = '相信明天会更好!' // 导出getTel export function getTel (){ return '13877889900' } function getHobby(){ return ['抽烟','喝酒','烫头'] } -
3.「创建 index.js」
// 引⼊school模块暴露的所有内容 import * as school from './school.js' // 引⼊student模块暴露的所有内容 import * as student from './student.js' -
4.「⻚⾯中引⼊ index.js」
<script type="module" src="./index.js"></script>
5.2. Node 中运⾏ ES6 模块
Node.js 中运⾏ ES6 模块代码有两种⽅式:
-
⽅式⼀:将
JavaScript⽂件后缀从.js改为.mjs,Node则会⾃动识别ES6模块。 -
⽅式⼆:在
package.json中设置type属性值为module。
5.3. 导出数据
ES6 模块化提供 3 种导出⽅式:①分别导出、②统⼀导出、③默认导出
-
1.「分别导出」
备注:在上⽅【初步体验中】环节,我们使⽤的导出⽅式就是【分别导出】
// 导出name export let name = {str:'NFIT'} // 导出slogan export const slogan = '珠海欢迎你!' // 导出getTel export function getTel (){ return '010-56253825' } -
2.「统⼀导出」
// 导出name export let name = {str:'NFIT'} // 导出slogan export const slogan = '珠海欢迎你!' function getTel (){ return '010-56253825' } function getCities(){ return ['北京','上海','深圳','成都','武汉','⻄安'] } // 统⼀导出了:name,slogan,getTel export {name,slogan,getTel} -
3.「默认导出」
const name = '张三' const motto = '⾛⾃⼰的路,让别⼈五路可⾛!' function getTel (){ return '13877889900' } function getHobby(){ return ['抽烟','喝酒','烫头'] } //默认导出:name,motto,getTel export default {name,motto,getTel}备注 :「上述多种导出⽅式,可以同时使⽤」
// 导出name ———— 分别导出 export let name = {str:'NFIT'} // 导出slogan export const slogan = '珠海欢迎你! function getTel (){ return '010-56253825' } function getCities(){ return ['北京','上海','深圳','成都','武汉','⻄安'] } // 导出slogan ———— 统⼀导出 export {slogan} // 导出getTel ———— 默认导出 export default getTel
5.4. 导⼊数据
对于 ES6 模块化来说,使⽤何种导⼊⽅式,要根据导出⽅式决定。
-
1.「导⼊全部」(通⽤)
可以将模块中的所有导出内容整合到⼀个对象中
import * as school from './school.js' -
2.「命名导⼊」(对应导出⽅式:分别导出、统⼀导出)
导出数据的模块
// 导出name ———— 分别导出 export let name = {str:'NFIT'} // 导出slogan export const slogan = '珠海欢迎你! function getTel (){ return '010-56253825' } function getCities(){ return ['北京','上海','深圳','成都','武汉','⻄安'] } //统⼀导出 export { getTel }命名导⼊:
import { name,slogan,getTel } from './school.js'通过 as 重命名:
import { name as myName,slogan,getTel } from './school.js' -
3.「默认导⼊」(对应导出⽅式:默认导出)
导出数据的模块
const name = '张三' const motto = '⾛⾃⼰的路,让别⼈五路可⾛!' function getTel (){ return '13877889900' } function getHobby(){ return ['抽烟','喝酒','烫头'] } //使⽤默认导出的⽅式,导出⼀个对象,对象中包含着数据 export default { name,motto,getTel }默认导⼊:
import student from './student.js' //默认导出的名字可以修改,不是必须为student -
4.「
命名导⼊与默认导⼊可以混合使⽤」导出数据的模块
// 导出name ———— 分别导出 export let name = {str:'NFIT'} // 导出slogan export const slogan = '珠海欢迎你! function getTel (){ return '010-56253825' } function getCities(){ return ['北京','上海','深圳','成都','武汉','⻄安'] } //统⼀导出 export default getTel「命名导⼊」与「默认导⼊」混合使⽤,且默认导⼊的内容必须放在前⽅:
import getTel,{name,slogan} from './school.js -
5.「动态导⼊」(通⽤)
允许在运⾏时
按需加载模块,返回值是⼀个 Promise。const school = await import('./school.js'); console.log(school) -
import 可以不接收任何数据
例如只是让 mock.js 参与运⾏
import './mock.js
此时,我们感受到模块化确实解决了:①全局污染问题、②依赖混乱问题、③数据安全问题。
使⽤原则:导出的常量,务必⽤ const 定义