一. 模块化开发
1. 概述
- 当下最重要的前端开发范式
- 通过把复杂代码按照功能的不同划分为不同模块
- 模块化仅仅是一个思想
2. 模块化的演变过程
- 一阶段
- 文件划分方式
- 把每个功能和数据单独存放到不同的文件中,约定每一个文件就是一个独立的模块,如果使用模块就通过 script 标签引入到页面中
- 缺点
- 污染全局作用域
- 命名冲突问题
- 无法管理模块与模块之间的依赖关系
- 完全依靠约定,项目上了体量之后,约定可能会被打破
- 二阶段
- 命名空间方式
- 把每个功能和数据挂载到一个对象下
- 三阶段
- IIFE
- 使用立即执行函数提供私有空间
- 实现了私有成员的概念
- 四阶段
- 模块化规范
- commonJS
- 一个文件就是一个模块
- 每个模块都有单独的作用域
- 通过 module.exports 导出成员
- 通过 require 函数载入模块
- commonJS 是以同步的方式加载模块
- AMD(Asynchronous Module Definition)
- Require.js 实现了 AMD 规范
- 约定每个模块必须通过 define 函数定义
- 通过 require 载入模块
- 目前绝大多数第三方库都支持 AMD 规范
- 缺点
- AMD 使用起来相对比较复杂
- 模块 JS 文件请求频繁
- Require.js 实现了 AMD 规范
3. 模块化标准规范
- node 环境中使用 commonJS 规范,浏览器环境中使用 ES Modules 规范
- ES Modules 是 ECMA Script 2015 中定义的模块系统
4. ES Modules
-
特性
- 通过给 script 标签添加 type="module" 的属性,就可以以 ES Module 的标准执行其中的 JS 代码
- ES Module 自动采用严格模式,忽略 use strict 的形式
- 每一个 ES Module 都运行在私有作用域中
- 在 ES Module 中,通过 CORS 的方式请求外部 JS 文件
- ES Module 中的 script 标签会自动延迟执行脚本
-
导出
// module.js // 修饰成员声明的方式 export var name = 'kjy' export function hello(){ console.log('hello') } export class Person{} // 整体导出 var name = 'kjy' function hello(){ console.log('hello') } class Person{} export { name, hello, Person } // 重命名 export { name as fooName, hello as fooHello, Person as fooPerson } // 导出默认成员 export default name // app.js import { name } from './module.js' // 重命名导入 import { fooName, fooHello, fooPerson } from './module.js' // 默认成员导入 export name from './module.js'
-
导入导出问题
- export { name, age },后面的花括号并不是字面量对象,而是 ES Module 导出语法
- export default { name, age },后边的花括号是一个字面量对象
- export 导出成员时,导出的是成员的引用
- 导出的成员引用是只读的
- import { name, age } from './module.js',import 后边的花括号并不是解构语法,而是 ES Module 的导入语法
- import 导入模块时,from 后边写的是导入模块的路径,必须使用完整的模块文件名称,不能省略 .js 的扩展名
- import 导入模块时,from 后边如果是相对路径,相对路径的 ./ 不能省略,否则会认为是第三方模块
- import {} from './module.js' 或 import './module.js' 会立即执行模块中的代码
- import * from './module.js',导入模块中所有的成员
- 不能使用 import 去 from 一个变量
- import 关键词必须出现在最顶层
- import('./module.js'),通过 import 函数动态的导入模块,这个函数返回一个 Promise,可以通过 .then(module => { console.log(module) }),的方式拿到导入成员
- 如果同时导出具名成员和默认成员,可以通过 import { name, age, default as title } from './module.js' 或 import title ,{ name, age } from './module.js' 的方式导入
-
ES Module 在 Node.js 的支持情况
- 可以在 Node.js 中 通过 ES Module 的方式载入原生的模块和第三方的模块
-
ES Module in Node.js - 与 CommonJS 交互
- ES Module 中可以载入 CommonJS 中所提供的成员
- 在 CommonJS 中,不能通过 require() 的方式载入 ES Module
- CommonJS 始终导出一个默认成员
- ES Module 中没有 CommonJS 中的模块全局成员