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
通常用作备用模块