模块化
传统开发模式的主要问题
- 命名冲突
- 文件依赖
通过模块化解决问题
- 模块化就是把单独的一个功能封装到一个模块(文件)中,模块之间相互隔离,但是可以通过特定的
接口
公开内部成员,也可以依赖别的模块 - 模块化开发的好处:方便代码的
重用
,从而提升开发效率
,并且方便后期的维护
浏览器端模块化规范
-
AMD
-
CMD
服务器端模块化规范
JavaScript 是一个强大面向对象语言,它有很多快速高效的解释器。然而, JavaScript 标准定义的 API 是为了构建基于浏览器的应用程序。并没有制定一个用于更广泛的应用程序的标准库。
CommonJS 规范的提出,主要是为了弥补当前 JavaScript 没有标准库的缺陷。
它的 终极目标就是:提供一个类似 Python,Ruby 和 Java 语言的标准库,而不只是让 JavaScript 停留在小脚本程序的阶段。
- 模块分为 单文件模块 与 包
- 模块成员导出:
module.exports
和exports
- 模块成员导入:
require('模块标识符')
// a.js
// 定义变量
let version = 1.0;
// 定义方法
const sayHi = name => `您好, ${name}`;
// 导出
exports.version = version;
exports.sayHi = sayHi;
// b.js
// 导入模块a
let a = require('./a.js');
// 输出 version 变量
console.log(a.version);
// 调用 sayHi方法
console.log(a.sayHi('CommonJS'));
module.exports.version = version;
module.exports.sayHi = sayHi;
exports是module.exports的别名(地址引用关系),导出对象最终以module.exports为准
当exports对象和moudle.exports对象指向的不是同一个对象时 以module.exports为准
ES6模块化
大一统的模块化规范 – ES6模块化
- 在 ES6 模块化规范诞生之前,Javascript 社区已经尝试并提出了 AMD、CMD、CommonJS 等模块化规范。
- 但是,这些社区提出的模块化标准,还是存在一定的差异性与局限性、并不是浏览器与服务器通用的模块化标准,例如:
- AMD 和 CMD 适用于浏览器端的 Javascript 模块化
- CommonJS 适用于服务器端的 Javascript 模块化
- 因此,ES6 语法规范中,在语言层面上定义了 ES6 模块化规范,是浏览器端与服务器端通用的模块化开发规范。
- ES6模块化规范中定义:
- 每个 js 文件都是一个独立的模块
- 导入模块成员使用
import 关键字
- 暴露模块成员使用
export 关键字
Node.js 中通过 babel
体验 ES6 模块化
Babel 是一个 JavaScript 编译器
Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。下面列出的是 Babel 能为你做的事情:
- 语法转换
- 通过 Polyfill 方式在目标环境中添加缺失的特性 (通过 @babel/polyfill 模块)
- 源码转换 (codemods)
npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
npm install --save @babel/polyfill
项目跟目录创建文件 babel.config.js
const presets = [
[
'@babel/env',
{
targets: {
edge: '17',
firefox: '60',
chrome: '67',
safari: '11.1',
},
},
],
]
module.exports = { presets }
通过 npx babel-node index.js
执行代码
默认导出 与 默认导入
- 默认导出语法
export default 默认导出的成员
- 默认导入语法
import 接收名称 from '模块标识符'
- 注意:每个模块中,只允许使用唯一的
一次
export default,否则会报错!
// m1.js
let a = 1
let b = 2
let c = 3
function show() {
console.log('123')
}
export default { a, b, show }
// index.js
import m1 from './m1.js'
console.log(m1)
// { a: 1, b: 2, show: [Function: show] }
按需导出 与 按需导入
- 按需导出语法
export let s1 = 10
- 按需导入语法
import { s1 } from '模块标识符'
- 注意:每个模块中,可以使用
多次
按需导出 - 默认导入和按需导入可以
一起
// m1.js
let a = 1
let b = 2
let c = 3
function show() {
console.log('123')
}
export default { a, b, show }
export let s1 = 'aaa'
export let s2 = 'ccc'
export function say() {}
// index.js
import m1, { s1, s2, say } from './m1.js'
console.log(m1)
// { a: 1, b: 2, show: [Function: show] }
console.log(s1) // aaa
console.log(s2) // ccc
console.log(say) // [Function: say]
直接导入并执行模块代码
只想执行某个模块中的代码,并不需要得到模块中向外暴露的成员,此时,可以直接导入并执行模块代码。
// m2.js
for(let i = 0; i < 3; i++) {
console.log(i)
}
// 直接导入并执行模块代码
import './m2.js'