模块化开发

439 阅读3分钟

一. 模块化开发

1. 概述

  • 当下最重要的前端开发范式
  • 通过把复杂代码按照功能的不同划分为不同模块
  • 模块化仅仅是一个思想

2. 模块化的演变过程

  • 一阶段
    • 文件划分方式
    • 把每个功能和数据单独存放到不同的文件中,约定每一个文件就是一个独立的模块,如果使用模块就通过 script 标签引入到页面中
    • 缺点
      • 污染全局作用域
      • 命名冲突问题
      • 无法管理模块与模块之间的依赖关系
      • 完全依靠约定,项目上了体量之后,约定可能会被打破
  • 二阶段
    • 命名空间方式
    • 把每个功能和数据挂载到一个对象下
  • 三阶段
    • IIFE
    • 使用立即执行函数提供私有空间
    • 实现了私有成员的概念
  • 四阶段
    • 模块化规范
    • commonJS
      • 一个文件就是一个模块
      • 每个模块都有单独的作用域
      • 通过 module.exports 导出成员
      • 通过 require 函数载入模块
      • commonJS 是以同步的方式加载模块
    • AMD(Asynchronous Module Definition)
      • Require.js 实现了 AMD 规范
        • 约定每个模块必须通过 define 函数定义
        • 通过 require 载入模块
      • 目前绝大多数第三方库都支持 AMD 规范
      • 缺点
        • AMD 使用起来相对比较复杂
        • 模块 JS 文件请求频繁

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 中的模块全局成员