Javascript 中的 CJS, AMD, UMD 和 ESM是什么
ES6之前,JS一直没有自己的模块体系,这一点对于大型项目的开发很不友好,所以社区出现了CommonJS和AMD(本人不熟悉),CommonJS主要是用于服务器(Node),AMD主要是用于浏览器。
但是ES6引入了ESM,到此,JS终于有了自己的模块体系,基本上可以完全取代CJS和AMD。
下面简单总结一下ESM以及ESM和CJS的区别。
一、CJS
CJS 是 CommonJS 的缩写。主要用于服务器端,主要使用如下:
// 导出
const obj = {a: 1};
module.exports = obj;
// 引入
const obj = require('./test.js');
二、ESM
ESM是ESModule,是ECMAScript自己的模块体系,是 Javascript 提出的实现一个标准模块系统的方案,于ES6引入, 代表 ES 模块。主要使用如下:
// 导出:export命令 export const obj = {name: 'E1e'}; // 默认导出 export default命令 export default {name: 'E1e'}; // 引入接口:import命令 // 引入普通导出 import { obj } from './test.js'; // 引入默认导出 import obj from './test.js';
可以在 HTML 中调用,只要如下
<script type="module"> import {func1} from 'my-lib'; func1(); </script>
在很多现代浏览器可以使用
它兼具两方面的优点:具有 CJS 的简单语法和 AMD 的异步
三、区别
commonJs 和 esModule 的区别
使用方式不同(以上);CJS 不能在浏览器中工作。它必须经过转换和打包
commonJs是被加载的时候运行,esModule是编译的时候运行
commonJs输出的是值的浅拷贝,esModule输出值的引用
commentJs具有缓存。在第一次被加载时,会完整运行整个文件并输出一个对象,拷贝(浅拷贝)在内存中。下次加载文件时,直接从内存中取值
commonJs 输出值拷贝
/*************** a.js**********************/ let count = 0 exports.count = count; // 输出值的拷贝 exports.add = ()=>{ //这里改变count值,并不会将module.exports对象的count属性值改变 count++; } /*************** b.js**********************/ const { count, add } = require('./a.js') //在支持es6模块的环境下等同于 import { count, add } from './a.js' console.log(count) //0 add(); console.log(count)//0
esModule 输出值引用
/*************** a.js**********************/ export let count = 0;//输出的是值的引用,指向同一块内存 export const add = ()=>{ count++;//此时引用指向的内存值发生改变 } /*************** b.js**********************/ import { count, add } from './a.js' console.log(count) //0 add(); console.log(count)//1
ES6 模块加载 CommonJS 模块
module.exports 等同于 export default 可以用 import 引入
CommonJS 模块加载 ES6 模块
CommonJS 模块加载 ES6 模块,不能使用require命令,而要使用import()函数。
exports 和 module.exports 的区别
module.exports 默认值为{}
exports 是 module.exports 的引用
exports 默认指向 module.exports 的内存空间
require() 返回的是 module.exports 而不是 exports
若对 exports 重新赋值,则断开了 exports 对 module.exports 的指向
引用:
require 和 import 都可引用
module.exports
//foo.js exports.foo="foo" //等同于 module.exports.foo="foo" //bar.js const { foo } = require('./foo.js') console.log(foo);//'foo'
exports
//foo.js exports={ foo: 'foo' } //bar.js const { foo } = require('./foo.js') //reuqire 返回的是 module.exports 对象, 默认为 {} console.log(foo);//undefined
四、其他模式
AMD
AMD 代表异步模块定义。下面是一个示例代码
define(['dep1', 'dep2'], function (dep1, dep2) { //Define the module value by returning a value. return function () {}; });
或者
// "simplified CommonJS wrapping" https://requirejs.org/docs/whyamd.html define(function (require) { var dep1 = require('dep1'), dep2 = require('dep2'); return function () {}; });
AMD 是异步(asynchronously)导入模块的(因此得名)
一开始被提议的时候,AMD 是为前端而做的(而 CJS 是后端)
AMD 的语法不如 CJS 直观。我认为 AMD 和 CJS 完全相反
UMD
UMD 代表通用模块定义(Universal Module Definition)。
(function (root, factory) { if (typeof define === "function" && define.amd) { define(["jquery", "underscore"], factory); } else if (typeof exports === "object") { module.exports = factory(require("jquery"), require("underscore")); } else { root.Requester = factory(root.$, root._); } }(this, function ($, _) { // this is where I defined my module implementation var Requester = { // ... }; return Requester; }));
在前端和后端都适用(“通用”因此得名)
与 CJS 或 AMD不同,UMD 更像是一种配置多个模块系统的模式。
当使用 Rollup/Webpack 之类的打包器时,UMD 通常用作备用模块
浙公网安备 33010602011771号