【模块化】:JS 模块化极简史

2022-03-30 21:06:13 浏览数 (1)

代码语言:javascript复制
目录
1. 什么是模块化?
2. 无模块化时代
3. 传统模块化阶段
  3.1. “对象”型模块
  3.2. “仿Java类”型模块
  3.3. “立即执行函数(IIFE)”型模块
  3.4. “全局变量输入”型模块
4. 百家争鸣:CommonJS、AMD、CMD
  4.1. CommonJS
  4.2. AMD
  4.3. CMD
5. 一统天下:ES6 Module

1. 什么是模块化?

模块化开发就是封装细节,提供使用接口,彼此之间互不影响,每个模块都是实现某一特定的功能。

——《软件工程》

在模块化编程中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为模块。

每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的。

——《Webpack官网》

有啥好处?

a. 避免命名冲突(不占全局命名空间);

b. 便于依赖管理(无须手动组织JS文件顺序);

c. 利于性能优化(异步模块加载);

e. 提高可维护性;

f. 利于代码复用;

2. 无模块化时代

最初,大家只是把项目中的功能,以文件为单位进行划分;这么干的结果是.....所有的变量、函数都暴露在全局作用域;多人协作开发时,极易出现命名冲突,也容易为了避免命名冲突,硬造一些稀奇古怪的名字....时间越长,麻烦越多...维护成本也越高...

3. 传统模块化阶段

这一阶段,WEB 开发人员主要是利用 JS 语言的闭包、原型、函数作用域等特性,减少对全局命名空间的污染;方式方法各有不同,但结果都差不多,比较混乱...

3.1. “对象”型模块

3.2. “仿Java类”型模块

3.3. “立即执行函数(IIFE)”型模块

3.4. “全局变量输入”型模块

注:上面仅列举了传统模块化方法中的几种常见代码组织形式,还有“放大型”、“宽松放大型”等其它方法,这里就不一一列举了,有兴趣可以看看下面这篇文章... http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html

传统模块化方法中

基本做到了让模块更独立、减少模块间冲突

但还有个更重要的问题没解决掉

如何清晰地描述模块间依赖

搞这么一大堆方法

优点肯定是有的

优点:传统模块化相比于无模块化时代,显然是进步的:减少了命名冲突,增强了模块的独立性;

但是

缺点同样明显

缺点: 1. 污染全局作用域:虽然我们通过各种手段尽力避免,但实际未从根本上解决; 2. 依赖关系不明显:对于大型项目,模块数量巨大,开发人员必须手动解决模块间依赖,这在复杂项目中极易出错维护成本高

4. 百家争鸣:CommonJS、AMD、CMD

JavaScript 在语言层面迟迟不推出模块化功能,这个背景下,各“民间组织”提出了CommonJSAMDCMD 模块化规范...

——《高手在民间》

4.1. CommonJS

Node.js的诞生,使JavaScript扩展到了服务器端, 为了让JavaScript在服务器端能跟Java、Phyton一样编写大型程序,于是有了CommonJS模块化规范;

(1). CommonJS是针对服务器端(非浏览器环境)的JavaScript开发,是Node.js的默认模块化规范; (2). CommonJS是一种只适用于JavaScript静态模块化规范注:只适用于JavaScript,意味着它无法把CSS等前端资源纳入模块化管理范围,但显然CSS也是组成前端模块的重要部分; 注:静态模块化规范,意味着它无法实现按需加载; (3). CommonJS所有模块均是同步阻塞式加载,无法实现异步加载; 注:服务器端加载模块是从硬盘直接读取,时间消耗和忽略不计;但浏览器端需要经网络下载,时间消耗取决于网速,同步加载策略容易出现“假死”,因此“同步阻塞式”加载策略不适用于浏览器环境

示例:

CommonJS是针对服务器端JavaScript的规范

但不适用于浏览器端

于是衍生出针对浏览器端的

AMD和CMD规范

4.2. AMD

AMD(Asynchronous Module Definition),异步模块定义;

实现:RequireJS; 特性:依赖前置,提前执行;

示例:

4.3. CMD

CMD(Common Module Definition),通用模块定义;CMD与AMD很类似,只是在模块的运行、解析时机上有所不同;

实现:SeaJS; 特性:依赖就近,延迟执行;

示例:

5. 一统天下:ES6 Module

ES6在语言规格的层面上实现了模块功能,而且实现的相当简单,完全可以取代现有的CommonJS、AMD和CMD规范,成为浏览器和服务器通用的模块解决方案

特点:

语言级、静态模块化规范; 实现按需加载的dynamic import语法提案现处于stage3阶段; 完全可替代CommonJS、AMD、CMD;

示例1(static import):

示例2(dynamic import):

总结一下

传统模块化手段:通过JS的闭包、对象、自执行函数等语言特性,避免模块间的命名冲突,提高模块的内聚性,但无统一编程标准,也无法把模块间的依赖关系描述清晰; CommonJS:Node.js让JavaScript延伸到“服务端”领域,促使针对“服务端”的JavaScript静态模块化规范CommonJS诞生,但此规范的“同步阻塞式”模块加载策略不适用于浏览器端环境; AMD,CMD:CommonJS规范的衍生品,支持模块“异步并行加载”,适用浏览器环境;AMD推崇“依赖前置”、CMD则是“依赖后置”;AMD规范的产物为RequireJS,CMD是SeaJS; ES6 Module:官方模块化标准,是语言的一部分,无需额外引入第三方库;ES6 Module同CommonJS一样,也是静态模块化规范,无法实现“按需加载”;但目前有一份处于stage3阶段的 dynamic import(tc39/proposal-dynamic-import)提案可用于动态模块加载;ES6完全可以取代CommonJS、AMD、CMD,成为浏览器和服务器端通用的模块化解决方案;

0 人点赞