这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战
背景
学习前端三个月了,准备刷刷面试题,总结总结,一天几道面试题,向大厂进军。
现在随着前端要求越来越高,各种各样的概念也随着而来,我们打包项目或者打包库的时候,一定遇到过我们到底需要打包成什么模块的问题,那我们今天就来了解下这些概念。
问题
AMD,CMD,CommonJS,ES6 Module,UMD,IIFE这些有什么区别?
看到这个题,这都是什么鬼啊,只听说过ES6 Module,其他的都不了解。
前端为什么要使用模块化
没有模块化,我们以前加载资源是不是都是这样加载。
这样加载有几个缺陷:
- 脚本的加载会阻塞DOM 树的渲染。
- 脚本与脚本之间引用不方便。
- 脚本之间如果有依赖关系,就必须顺序加载,不方便维护。
- 发起多次请求。
- 基于以上原因,不适合大型应用。
模块化开发,一个模块就是一个实现特定功能的文件,有了模块我们就可以方便的使用别人的代码,需要什么功能就加载什么模块。
模块化的好处:
- 避免变量污染,命名冲突。
- 提高代码复用率。
- 提高维护性。
- 依赖关系的管理。
AMD(浏览器端)
Asynchronous Module Definition,中文名是异步模块。它是一个在浏览器端模块化开发的规范,由于不是js原生支持,使用AMD规范进行页面开发需要用到对应的函数库,也就是大名鼎鼎的RequireJS,实际上AMD是RequireJS在推广过程中对模块定义的规范化的产出。
AMD 的代表作require.js
- require.js 会自动分析依赖关系,将需要加载的模块正确加载。
- requirejs 为全局添加了 define 函数,按照这种约定(AMD)书写模块即可。
调用方式:
我们可以看到AMD的写法主要是define,require,依赖必须提前声明好。
CMD(浏览器端)
全称:Common Module Definition。它是一个在浏览器端模块化开发的规范,在Sea.js 中,所有 JavaScript 模块都遵循 CMD规范。
CMD 的代表作sea.js 书写格式如下:
define(factory)
我们来看具体代码:
CMD的特点是:依赖就近编写,动态引入依赖文件。
AMD与CMD的区别
- CMD 推崇依赖就近,AMD 推崇依赖前置
- 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。
其实AMD与CMD都是异步加载。
CommonJS(服务端)
CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。
代表:nodejs
主要写法:module.exports,require 特点:同步加载
UMD
UMD 叫做通用模块定义规范(Universal Module Definition)。也是随着大前端的趋势所诞生,它可以通过运行时或者编译时让同一个代码模块在使用 CommonJs、CMD 甚至是 AMD 的项目中运行。未来同一个 JavaScript 包运行在浏览器端、服务区端甚至是 APP 端都只需要遵守同一个写法就行了。
它集结了CommonJS,CMD,AMD的规范于一身。自适配模块方案
ES6 Module(服务器和浏览器通用)
ECMAScript2015 规定了新的模块加载方案。
代码使用:
主要写法:export ,import ,依赖提前声明好。
ES6与CommonJS的区别
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
- CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。
ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令 import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的 import 有点像 Unix 系统的“符号连接”,原始值变了,import 加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
IIFE
IIFE( 立即调用函数表达式)是一个在定义时就会立即执行的函数。
写法:
(function(){....})();
js中可以直接使用。
转换ES6 Module
babel
鉴于浏览器支持度的问题,如果要使用 ES6 的语法,一般都会借助 babel
Babel 是一个 JavaScript 编译器。
Babel 只是把 ES6 模块语法转为 CommonJS 模块语法,然而浏览器是不支持这种模块语法的,所以直接跑在浏览器会报错的,如果想要在浏览器中运行,还是需要使用打包工具将代码打包。
webpack
Babel 将 ES6 模块转为 CommonJS 后, webpack 又是怎么做的打包的呢?它该如何将这些文件打包在一起,从而能保证正确的处理依赖,以及能在浏览器中运行呢?
首先为什么浏览器中不支持 CommonJS 语法呢?
这是因为浏览器环境中并没有 module、 exports、 require 等环境变量。
打包工具做的事情就是补充全这些环境变量,类似于垫片的作用。
结语
一步一步慢慢来,踏踏实实把活干!