第 26 题:介绍模块化发展历程
当我们要完成一个应用的时候,会根据对应的功能划分为许多不同的模块,就像一个论坛,有发帖的模块,评论的模块,js 中的模块也正是如此,一个具体功能的代码抽成一个文件,当你做一个东西的时候需要用到这个功能的时,可以直接使用这个文件,实现功能的分离,并能在多个需要的地方使用。就像是螺丝钉、螺丝帽、垫片一样的,通过组合使用实现出你的产品。
通过直白的描述,我们可以知道,模块化的好处就是,抽离代码,重复使用,如现在很直观的代表 npm 包。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
1、CommonJS
CommonJS 规范概述了同步声明依赖的模块定义。这个规范主要用于在服务器端实现模块化代码组 织,但也可用于定义在浏览器中使用的模块依赖。CommonJS 模块语法不能在浏览器中直接运行。
CommonJS 模块定义需要使用 require()指定依赖,而使用 exports 对象定义自己的公共 API。如下例:
无论一个模块在 require()中被引用多少次,模块永远是单例。模块第一次加载后会被缓存,后续加载会取得缓存的模块。
如下例,moduleA只会被打印一次,这是因为无论请求多少次,ModuleA只会被加载一次。
module.exports 对象非常灵活,有多种使用方式。如下例:
只导出一个实体,也可以到处多个对象。
2、异步模块定义(AMD):由于CommonJS以服务器端为目标环境,能够一次性把所有模块都加载到内存,而异步模块定义(AMD)的模块定义系统则以浏览器为目标执行环境,这需要考虑网络延迟的问题。
AMD的一般策略:让模块声明自己的依赖,而运行在浏览器中的模块系统会按需获取依赖,并在依赖加载完成后立即执行依赖它们的模块。
AMD模块实现的核心是用函数包装模块定义:这样可以防止声明全局变量,并允许加载器库控制何时加载模块。
与CommonJS不同,AMD支持可选的为模块指定字符串标识符。
例子:
AMD 也支持 require 和 exports 对象,通过它们可以在 AMD 模块工厂函数内部定义 CommonJS
风格的模块。这样可以像请求模块一样请求它们,但 AMD 加载器会将它们识别为原生 AMD 结构
3、通用模块定义UMD:为了统一CommonJS和AMD生态系统,通用模块定义(UMD,Universal Module Definition)规范应运而生。UMD可用于创建这两个系统都可以使用的模块代码。
本质上:UMD定义的模块会在启动时检测要使用哪个模块系统,然后进行适当配置,并把所有逻辑包装在一个立即调用的函数表达式(IIFE)中。
此模式有支持严格 CommonJS 和浏览器全局上下文的变体。不应该期望手写这个包装函数,它应该
由构建工具自动生成。开发者只需专注于模块的内由容,而不必关心这些样板代码。
4、使用ES6模块:ES6 最大的一个改进就是引入了模块规范。这个规范全方位简化了之前出现的模块加载器,原生浏
览器支持意味着加载器及其他预处理都不再必要。从很多方面看,ES6 模块系统是集 AMD 和 CommonJS
之大成者。
ECMAScript 6 模块是作为一整块 JavaScript 代码而存在的。带有 type="module"属性的<script> 标签会告诉浏览器相关代码应该作为模块执行,而不是作为传统的脚本执行。模块可以嵌入在网页中, 也可以作为外部文件引入:
嵌入的模块定义代码不能使用 import 加载到其他模块。只有通过外部文件加载的模块才可以使用import 加载。因此,嵌入模块只适合作为入口模块。
参考这篇文章吧前端科普系列-CommonJS:不是前端却革命了前端
第一阶段——无模块化
将所有JS文件都放在一块,代码执行顺序就按照文件的顺序执行。
缺点是污染全局作用域。每一个模块都是暴露在全局中的,容易产生命名冲突。
还有要手动处理各代码的依赖关系。
第二阶段——commonJS规范
是一个JavaScript模块化的规范,一个文件就是一个模块,内部定义的变量就属于这个模块里的,不会对外暴露,所以不会污染全局变量。
第三阶段——AMD规范
因为commonJS规范不适用于浏览器,因为要从服务器加载文件,不能用同步模式,所以有了AMD规范,该规范的实现,就是requireJs了。
依赖前置,require([dep1, dep2],callback),先加载依赖再执行回调函数
优点是可以在浏览器环境中异步加载模块,而且可以并行加载多个模块
第四阶段——CMD规范
和requirejs非常类似,即一个js文件就是一个模块,但是可以通过按需加载的方式,而不是必须在模块开始就加载所有的依赖。
第五阶段——ES6的模块化
使用ES6的语法,export和import实现模块化,用的比较多就不介绍了。缺点是浏览器暂不支持,需要babel编译过
特殊规范——UMD
兼容AMD,CommonJS 模块化语法。
总结:
这篇文章划分得比较清晰
很酷
可从IIFE、AMD、CMD、CommonJS、UMD、webpack(require.ensure)、ES Module、
<script type="module">
这几个角度考虑。AMD,CMD用的不多,主要讲一下CommonJS和ESModule
模块的特性
CommonJS
特点:
require
、module.exports
、exports
CommonJS 一般用在服务端或者Node用来同步加载模块,它对于模块的依赖发生在代码运行阶段,不适合在浏览器端做异步加载。
exports
实际上是一个对module.exports
的引用:但注意,不能给
exports
赋值,否则会断开与module.exports
的连接。ES6 Module
特点:
import
、export
ES6模块化不是对象,
import
会在JavaScript引擎静态分析,在编译时就引入模块代码,而并非在代码运行时加载,因此也不适合异步加载。在HTML中如果要引入模块需要使用
ESModule的优势:
二者的差异
CommonJS模块引用后是一个值的拷贝,而ESModule引用后是一个值的动态映射,并且这个映射是只读的。
import
后生成一个引用链接,在脚本真正执行时才会根据这个引用链接去模块里面取值,模块内部的原始值变了import
加载的模块也会变。CommonJS运行时加载,ESModule编译阶段引用。
export
暴露出要输出的代码块,在import
时使用静态命令的方法引用指定的输出代码块,并在import
语句处执行这个要输出的代码,而不是直接加载整个模块。模块化
模块化的作用
模块化是为了处理全局污染和依赖管理混乱的问题
模块化
因为一开始js本身没有提供模块化的机制,所以才会衍生出commonJS、AMD、CMD和UMD这么多模块化规范。js在ES6时原生提供了import和export模块化机制
commonJS
定义
文件即模块,每个文件通过module来表示,用require来引用其他依赖,用module.exports来导出自身
机制
通过require去引用文件时,会将文件执行一遍后,将其执行结果通过浅克隆的方式,写入全局内存。后续再require该路径,就直接从内存里取出,不需要重新执行对应的文件
特点
commonJS是服务器编程范式,因为服务器上所有文件都在硬盘里,通过同步加载的方式即可,所以该规范是同步加载规范。同时它是在运行时加载,也就是你可以在require里拼接变量,在加载时会自动识别出最终的实际路径
AMD
定义
define(module, [dep1, dep2], callback)
机制
通过require加载时,它会先加载对应的依赖,等依赖资源加载完之后,会执行回调函数,将依赖作为入参,执行对应的业务逻辑
特点
AMD机制是浏览器编程范式,它是在客户端使用的,由于资源都是在服务器上,所以它是异步加载。同时,它最大的特点是强调依赖前置。
CMD
定义
机制和AMD类似,最大的区别就是CMD强调延迟加载,对应的依赖等到回调函数里执行具体依赖语句,才会去加载,但是AMD在后续版本里也支持了延迟加载的写法
机制
同上
特点
同上
UMD
定义
CommonJS、AMD、CMD并行的状态下,就需要一种方案能够兼容他们,这样我们在开发时,
就不需要再去考虑依赖模块所遵循的规范了,而UMD的出现就是为了解决这个问题。
ES6
定义
通过import引入依赖,通过export导出依赖
机制
ES6的模块机制在依赖模块时并不会先去预加载整个脚本,而是生成一个只读引用,并且静态解析依赖,等到执行代码时,再去依赖里取出实际需要的模块
特点
编译时加载,不允许在里边引用变量,必须为真实的文件路径。可以通过调用import()语句,会生成一个promise去加载对应的文件,这样子就是运行时加载,可以在路径里边编写变量
太棒了!
var fs = require('fs'):
import a from 'a';
es6,amd,smd,commonjs 思维导图
模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。
IIFE: 使用自执行函数来编写模块化,特点:在一个单独的函数作用域中执行代码,避免变量冲突。
AMD: 使用requireJS 来编写模块化,特点:依赖必须提前声明好。
CMD: 使用seaJS 来编写模块化,特点:支持动态引入依赖文件。
CommonJS: nodejs 中自带的模块化。
UMD:兼容AMD,CommonJS 模块化语法。
webpack(require.ensure):webpack 2.x 版本中的代码分割。
ES Modules: ES6 引入的模块化,支持import 来引入另一个 js 。
参考:模块化
很cool