Javascript 中的 CJS, AMD, UMD 和 ESM是什么

ES6之前,JS一直没有自己的模块体系,这一点对于大型项目的开发很不友好,所以社区出现了CommonJSAMD(本人不熟悉),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 通常用作备用模块

posted @ 2021-10-12 15:00  一心二念  阅读(2412)  评论(0编辑  收藏  举报