1.ES6 Module
javascript在ES2015(ES6)中出现了语言层面的模块(module)。
ES6的模块既可以用于浏览器端,也可以用于服务器端(nodeJS)。
ES6模块是静态化的模块加载,可以实现静态优化,在编译时就可以分析确认模块的依赖和输入输出变量。
webpack中TreeShaking的实现就是依赖于该性质。
而AMD和CommonJS是在运行时才能确认这些东西。
2. AMD
在此之前,浏览器端使用的模块加载方案主要是AMD,基于require.js;
AMD和CMD其实都是浏览器端的异步模块加载规范;
AMD是RequireJS输出的规范;CMD是seaJS输出的规范;
用法
// 1. 想在页面中使用AMD加载模块,需要手动引入require.js <script src="https://cdn.bootcss.com/require.js/2.3.6/require.js" data-main="main.js" defer async="true"></script> // 2. 每一个文件是一个模块,AMD要求模块使用define()定义模块 // test.js 模块 define(['jquery'], function(){ // 前面的数组表示依赖的模块 return function test() { console.log(test); } }) // 3. 在main.js中引入test.js require(['tset'], function(test) { test() })
3.CommonJS
ES6之前,服务器端(nodeJS)是CommonJS规范。
09年,nodejs项目是使用CommonJS规范实现的模块系统。
有一个全局的require()方法。
// 返回结果就是模块名字 // CommonJS里面的require用法和AMD里面的require用法不一致 let {readFile} = require('fs');
导出是module.exports = {}
⚠️: CommonJS输出的值是缓存,不是实时数据。但是ES6的export命令导出的是接口,可以访问模块的实时数据。
CommonJS第一次require,就会执行整个脚本,并在内存中生成一个对象(缓存):
{ id: 'xxx', //模块名, exports: {...}, //输出的拷贝 loaded: true/false // 加载是否完成 ... }
以后再require该模块,直接到缓存中取exports对象的值。
即无论执行加载多少次,返回的都是第一次加载时返回的值。可以手动清空缓存,清除之前的运行结果。
4. UMD
通用模块化系统,兼容AMD和CommonJS;
通常以AMD为基础,然后再包裹一层特殊代码实现CommonJS的兼容性。