左小白的技术日常
Github

AMD、UMD、CommonJS、ES Modules的理解

这篇文章发布于 2020/11/23,归类于
标签:
AMDUMDCommonJSES Modules

在 ES6 之前,JS 本身没有模块功能,社区出现了 CommonJS 和 AMD 等模块方案。从 ES6 开始, JS 开始原生支持模块,一般称之为 ES Modules。

/*
 * bundle.js  UMD webpack打包后的js
 * 判断define为函数,并且是否存在define.amd,来判断是否为AMD规范,
 * 判断module是否为一个对象,并且是否存在module.exports来判断是否为CommonJS规范
 * 如果以上两种都没有,设定为原始的代码规范。
 */
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global = global || self, global.myBundle = factory());
}(this, (function () { 'use strict';

    var main = () => {
        return 'hello world';
    };

    return main;

})));
// index.html
<script src="bundle.js"></script>
<script>
  console.log(myBundle());
</script>

区别:

  1. CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。CommonJS一旦输出一个值,模块内部的变化就影响不到这个值。ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
  2. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
  3. CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。
// CommonJS模块
let { stat, exists, readfile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

// ES6模块
import { stat, exists, readFile } from 'fs';

参考