zhangdizhangdi

模块化

文章

什么是前端模块化

  • 将复杂程序根据规范拆分成若干模块,一个模块包括输入和输出
  • 模块的内部实现是私有的,对外暴露接口与其它模块通信

进化过程

  1. 全局 function 模式,将不同功能封装成不同函数

    缺陷:容易引发全局命名空间冲突

  2. 全局 namespace 模式,通过对象封装模块

    缺陷:外部能够修改模块内部数据

js
window.__Module ={
  x:1,
  api(){
    return{...}
  }
}

const m = window.__Module
const a = m.api()
m.x = 2 //模块内应该是私有的,外面不可随意修改
  1. IIFE 模式,通过自执行函数创建闭包 函数作用域与闭包

    缺陷:无法解决模块间相互依赖问题

  2. IIFE 模式增强,支持传入自定义依赖

    缺陷:

    • 多依赖传入时,代码阅读困难
    • 无法支持大规模的模块化开发
    • 无特定语法支持,代码简陋

CommonJS

node 中的 cjs 模块加载采用同步加载方式

通过require加载模块,通过exportsmodule.exports输出模块

特点

  • 所有代码都运行在模块作用域,不会污染全局作用域
  • 模块可以多次加载,第一次加载时会运行模块,模块输出结果会被缓存,再次加载时,会从缓存结果中直接读取模块输出结果
  • 模块加载的顺序,按照其在代码中出现的顺序
  • 模块输出的值是值的拷贝,类似 IIFE 方案中的内部变量

require()绝对路径或相对路径

module.exports会覆盖掉exports的结果

ESModule

ESModule设计理念是希望在编译时就确定模块依赖关系及输入输出

ESM 通过 import 加载模块,通过 export 输出模块

CommonJS 和 ESModule 对比

  • CommonJS 模块输出的是值的拷贝,ESM 模块输出的是值的引用
  • CommonJS 模块是运行时加载,ESM 模块是编译时输出接口
  • CommonJS 是单个值导出,ESM 可以导出多个
  • CommonJS 模块是同步加载,ESM 支持异步加载

    import(xxx).then('...')

  • CommonJS 的 this 是当前模块,ESM 的 this 是 undefined
  • 二者语法不同
  • CommonJS 是 node 默认采用的模块化规范,node 14 后默认支持 ESM;ESM 浏览器默认采用的模块化规范

AMD

Asynchronous Module Definition,异步模块定义。

require.js

js
define("app.js", ["a.js", "b.js"], function (ajs, bjs) {
    var exports = { name: "I am app.js" }
    return exports;
}

require(['math'], function(math) {
  math.add(2, 3);
})

CMD

Common Module Definition,通用模块定义。

sea.js

AMD 推崇依赖前置、提前执行,CMD 推崇依赖就近、延迟执行

js
define(function (require, exports, module) {
  var a = require('./a')
  a.doSomething()
  var b = require('./b')
  b.doSomething()
})

UMD

Universal Module Definition,通用模块定义。

UMD 是 AMD 和 CommonJS 的一个糅合。AMD 是浏览器优先,异步加载;CommonJS 是服务器优先,同步加载。

js
;(function (window, factory) {
  if (typeof exports === 'object') {
    module.exports = factory()
  } else if (typeof define === 'function' && define.amd) {
    define(factory)
  } else {
    window.eventUtil = factory()
  }
})(this, function () {
  //module ...
})